From: mike The GNU LGPL applies to the CUPS API library, located in the "cups"
subdirectory of the CUPS source distribution and in the
-"/usr/include/cups" directory and "libcups.a", "libcups.sl", or
-"libcups.so" files in the binary distributions.
+"/usr/include/cups" directory and "libcups.a", "libcups_s.a",
+"libcups.sl", or "libcups.so" files in the binary distributions.
The GNU GPL applies to the remainder of the CUPS distribution,
including the "pstoraster" filter which is based upon GNU Ghostscript
-5.50 and the "pdftops" filter which is based upon Xpdf 0.90.
+5.50 and the "pdftops" filter which is based upon Xpdf 0.93a.
For those not familiar with the GNU GPL, the license basically
allows you to:
@@ -93,7 +93,7 @@ Fax: +1.415.492.9862 The "pdftops" filter is based on the Xpdf 0.90 software. For binary
+ The "pdftops" filter is based on the Xpdf 0.93a software. For binary
distribution licensing of this software, please contact:
CUPS provides a portable printing layer for UNIX®-based operating
-systems. It has been developed by Easy
-Software Products to promote a standard printing solution for all
-UNIX vendors and users. CUPS provides the System V and Berkeley
-command-line interfaces. CUPS uses the Internet Printing Protocol ("IPP") as the basis for
-managing print jobs and queues. The Line Printer Daemon ("LPD") Server
-Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
-also supported with reduced functionality. CUPS adds network printer
-browsing and PostScript Printer Description ("PPD") based printing
-options to support real-world printing under UNIX. CUPS also includes a customized version of GNU Ghostscript
-(currently based off GNU Ghostscript 5.50) and an image file RIP that
-are used to support non-PostScript printers. Sample drivers for HP and
-EPSON printers are included that use these filters. CUPS provides a portable printing layer for UNIX®-based operating
+ systems. It has been developed by Easy
+ Software Products to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces. CUPS uses the Internet Printing Protocol ("IPP") as the basis for
+ managing print jobs and queues. The Line Printer Daemon ("LPD") Server
+ Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description ("PPD") based printing
+ options to support real-world printing under UNIX. CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters. The following CUPS documentation is referenced by this document: The following CUPS documentation is referenced by this document: The following non-CUPS documents are referenced by this document: The following non-CUPS documents are referenced by this document: Documentation on the CVS software is included with the whitepaper,
-"CVS II: Parallelizing Software Development". Documentation on the CVS software is included with the whitepaper,
+ "CVS II: Parallelizing Software Development". When the sub-system(s) involved have been identified, an engineer
-will then determine the change(s) needed and estimate the time required
-for the change(s). When the sub-system(s) involved have been identified, an engineer
+ will then determine the change(s) needed and estimate the time required
+ for the change(s). Functions with a local scope shall be declared "static" and be
-lowercase with underscores between words ("do_this", "do_that",
-"do_something_else", etc.) Functions with a local scope shall be declared "static" and be
+ lowercase with underscores between words ("do_this", "do_that",
+ "do_something_else", etc.) Variables with a local scope shall be lowercase with underscores
-between words ("this_variable", "that_variable", etc.) Any local
-variables shared by functions within a source file shall be declared
-"static". Variables with a local scope shall be lowercase with underscores
+ between words ("this_variable", "that_variable", etc.) Any local
+ variables shared by functions within a source file shall be declared
+ "static". Typed enumerations shall be used whenever possible to allow for type
-checking by the compiler. Typed enumerations shall be used whenever possible to allow for type
+ checking by the compiler. This interface design description document provides detailed file
-formats, message formats, and program conventions for the Common UNIX
-Printing System ("CUPS") Version 1.1. This interface design description document provides detailed file
+ formats, message formats, and program conventions for the Common UNIX
+ Printing System ("CUPS") Version 1.1. CUPS provides a portable printing layer for UNIX®-based operating
-systems. It has been developed by Easy
-Software Products to promote a standard printing solution for all
-UNIX vendors and users. CUPS provides the System V and Berkeley
-command-line interfaces. CUPS uses the Internet Printing Protocol ("IPP") as the basis for
-managing print jobs and queues. The Line Printer Daemon ("LPD") Server
-Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
-also supported with reduced functionality. CUPS adds network printer
-browsing and PostScript Printer Description ("PPD") based printing
-options to support real-world printing under UNIX. CUPS also includes a customized version of GNU Ghostscript
-(currently based off GNU Ghostscript 5.50) and an image file RIP that
-are used to support non-PostScript printers. Sample drivers for HP and
-EPSON printers are included that use these filters. CUPS provides a portable printing layer for UNIX®-based operating
+ systems. It has been developed by Easy
+ Software Products to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces. CUPS uses the Internet Printing Protocol ("IPP") as the basis for
+ managing print jobs and queues. The Line Printer Daemon ("LPD") Server
+ Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description ("PPD") based printing
+ options to support real-world printing under UNIX. CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters. This interface design description document is organized into the
-following sections: This interface design description document is organized into the
+ following sections: The following CUPS documentation is referenced by this document: The following CUPS documentation is referenced by this document: The following non-CUPS documents are referenced by this document: The following non-CUPS documents are referenced by this document: The character set files define a mapping between 8-bit characters
-and the Unicode character set, or between Unicode and printer fonts.
-They are named using the IETF charset names defined in RFCnnnn. These
-files are ASCII text, the content of which is described below. Comments
-can be included by using the # character in the first column
-of a line. The character set files define a mapping between 8-bit characters and
+ the Unicode character set, or between Unicode and printer fonts. They
+ are named using the IETF charset names defined in RFCnnnn. These files
+ are ASCII text, the content of which is described below. Comments can
+ be included by using the # character in the first column of a
+ line. 8-bit character set files start with a line reading: 8-bit character set files start with a line reading: Following this are lines that define the font information: Following this are lines that define the font information: First and last are the first and last glyphs
-in the font mapping that correspond to that font; a maximum of 256
-characters can be mapped within each group, with a maximum of 256
-mappings (this is a PostScript limitation.) The glyph values are
-hexadecimal. Direction is the string "ltor", "rtol", or "rtola"
-indicating left-to-right, right-to-left, or right-to-left Arabic text. Width is the string "single" or "double"; double means
-that the glyphs are twice as wide as ASCII characters in the Courier
-typeface. Normal, bold, italic, and bold-italic are the
-typefaces to use for each presentation. If characters are only
-available in a single style then only one typeface should be listed
-(e.g. "Symbol".) Each font that is listed will be used (and downloaded
-if needed) when printing. The remaining lines define a character to Unicode glyph mapping for
-the character set. The character and glyph values are hexadecimal: First and last are the first and last glyphs in
+ the font mapping that correspond to that font; a maximum of 256
+ characters can be mapped within each group, with a maximum of 256
+ mappings (this is a PostScript limitation.) The glyph values are
+ hexadecimal. Direction is the string "ltor", "rtol", or "rtola"
+ indicating left-to-right, right-to-left, or right-to-left Arabic text. Width is the string "single" or "double"; double means
+ that the glyphs are twice as wide as ASCII characters in the Courier
+ typeface. Normal, bold, italic, and bold-italic are the
+ typefaces to use for each presentation. If characters are only
+ available in a single style then only one typeface should be listed
+ (e.g. "Symbol".) Each font that is listed will be used (and downloaded
+ if needed) when printing. The remaining lines define a character to Unicode glyph mapping for
+ the character set. The character and glyph values are hexadecimal: Unicode character set files start with a line reading: Unicode character set files start with a line reading: Encoding is the encoding to use for the text; currently
-only the string "utf8" is supported. Following this are lines defining the font information: Encoding is the encoding to use for the text; currently
+ only the string "utf8" is supported. Following this are lines defining the font information: First and last are the first and last glyphs
-in the font mapping that correspond to that font; a maximum of 256
-characters can be mapped within each group, with a maximum of 256
-mappings (this is a PostScript limitation.) The glyph values are
-hexadecimal. Direction is the string "ltor", "rtol", or "rtola"
-indicating left-to-right, right-to-left, or right-to-left Arabic text. Width is the string "single" or "double"; double means
-that the glyphs are twice as wide as ASCII characters in the Courier
-typeface. Normal, bold, italic, and bold-italic are the
-typefaces to use for each presentation. If characters are only
-available in a single style then only one typeface should be listed
-(e.g. "Symbol".) Each font that is listed will be used (and downloaded
-if needed) when printing. First and last are the first and last glyphs in
+ the font mapping that correspond to that font; a maximum of 256
+ characters can be mapped within each group, with a maximum of 256
+ mappings (this is a PostScript limitation.) The glyph values are
+ hexadecimal. Direction is the string "ltor", "rtol", or "rtola"
+ indicating left-to-right, right-to-left, or right-to-left Arabic text. Width is the string "single" or "double"; double means
+ that the glyphs are twice as wide as ASCII characters in the Courier
+ typeface. Normal, bold, italic, and bold-italic are the
+ typefaces to use for each presentation. If characters are only
+ available in a single style then only one typeface should be listed
+ (e.g. "Symbol".) Each font that is listed will be used (and downloaded
+ if needed) when printing. The language files define the default character set and a collection
-of text messages in that language. They are named by prefixing the
-string "cups_" to the front of the language specifier (e.g. "cups_en",
-"cups_fr", etc.) Each file consists of two or more lines of ASCII text. The first line identifies the character set to be used for the
-messages. The currently recognized values are: The language files define the default character set and a collection
+ of text messages in that language. They are named by prefixing the
+ string "cups_" to the front of the language specifier (e.g. "cups_en",
+ "cups_fr", etc.) Each file consists of two or more lines of ASCII text. The first line identifies the character set to be used for the
+ messages. The currently recognized values are: The second and succeeding lines define text messages. If the message
-text is preceded by a number, then the current message number is
-updated and the text after the number is used. The second and succeeding lines define text messages. If the message
+ text is preceded by a number, then the current message number is
+ updated and the text after the number is used. CUPS uses two MIME files in its standard configuration. CUPS uses two MIME files in its standard configuration. The mime.types file defines the recognized file types and consists
-of 1 or more lines of ASCII text. Comment lines start with the pound
-("#") character. The backslash ("\") character can be used at the end
-of a line to continue that line to the next. Each non-blank line starts with a MIME type identifier
-("super/type") as registered with the IANA. All text following the MIME
-type is treated as a series of type recognition rules: The mime.types file defines the recognized file types and consists of
+ 1 or more lines of ASCII text. Comment lines start with the pound ("#")
+ character. The backslash ("\") character can be used at the end of a
+ line to continue that line to the next. Each non-blank line starts with a MIME type identifier ("super/type")
+ as registered with the IANA. All text following the MIME type is
+ treated as a series of type recognition rules: The The The mime.types file defines the recognized file filters and consists
-of 1 or more lines of ASCII text. Comment lines start with the pound
-("#") character. Each non-blank line starts with two MIME type identifiers
-("super/type") representing the source and destination types. Following
-the MIME types are a cost value (0 to 100) and the filter program to
-use. If the filter program is not specified using the full path then it
-must reside in the CUPS filter directory: The mime.types file defines the recognized file filters and consists
+ of 1 or more lines of ASCII text. Comment lines start with the pound
+ ("#") character. Each non-blank line starts with two MIME type identifiers
+ ("super/type") representing the source and destination types. Following
+ the MIME types are a cost value (0 to 100) and the filter program to
+ use. If the filter program is not specified using the full path then it
+ must reside in the CUPS filter directory: CUPS maintains user-defined printer and option files for each
-printer and user on the system. The printers and options defined in the
-system option file ( CUPS maintains user-defined printer and option files for each printer
+ and user on the system. The printers and options defined in the system
+ option file ( The line beginning with "Default" indicates the default destination
-for print jobs; a default line in the user option file overrides the
-default defined in the system option file. Name is the name of a printer known to the local server. Instance can be any string of letters, numbers, and the
-underscore up to 127 characters in length. The remainder of the line contains a list of space-separated options
-and their values. The line beginning with "Default" indicates the default destination
+ for print jobs; a default line in the user option file overrides the
+ default defined in the system option file. Name is the name of a printer known to the local server. Instance can be any string of letters, numbers, and the
+ underscore up to 127 characters in length. The remainder of the line contains a list of space-separated options
+ and their values. PostScript Printer Description ("PPD") files describe the
-capabilities of each printer and are used by CUPS to support
-printer-specific features and intelligent filtering. PostScript Printer Description ("PPD") files describe the
+ capabilities of each printer and are used by CUPS to support
+ printer-specific features and intelligent filtering. The PPD file format is described in
- Adobe TechNote #5003: PostScript Printer Description File Format
-Specification Version 4.3. The PPD file format is described in
+ Adobe TechNote #5003: PostScript Printer Description File Format
+ Specification Version 4.3. CUPS adds several new attributes that are described below. CUPS adds several new attributes that are described below. This string attribute provides a conversion rule of the form: This string attribute provides a conversion rule of the form: The destination type is assumed to the printer's type. If a printer
-supports the source type directly the special filter program "-" may be
-specified. The destination type is assumed to the printer's type. If a printer
+ supports the source type directly the special filter program "-" may be
+ specified. This boolean attribute notifies the RIP filters that the destination
-printer does not support copy generation in hardware. The default value
-is false. This boolean attribute notifies the RIP filters that the destination
+ printer does not support copy generation in hardware. The default value
+ is false. This integer attribute specifies a printer-specific model number.
-This number can be used by a filter program to adjust the output for a
-specific model of printer. This integer attribute specifies a printer-specific model number.
+ This number can be used by a filter program to adjust the output for a
+ specific model of printer. This string attribute specifies a color profile of the form: This string attribute specifies a color profile of the form: The resolution and type values may be "-" to act as a
-wildcard. Otherwise they must match one of the The density and gamma values define gamma and density
-adjustment function such that: The resolution and type values may be "-" to act as a
+ wildcard. Otherwise they must match one of the The density and gamma values define gamma and density
+ adjustment function such that: The m00 through m22 values define a 3x3 transformation
-matrix for the CMY color values. The density function is applied
-after the CMY transformation. The m00 through m22 values define a 3x3 transformation
+ matrix for the CMY color values. The density function is applied
+ after the CMY transformation. This required attribute describes which version of the CUPS IDD was
-used for the PPD file extensions. Currently it must be the string "1.0"
-or "1.1". This required attribute describes which version of the CUPS IDD was
+ used for the PPD file extensions. Currently it must be the string "1.0"
+ or "1.1". The scheduler reads three configuration files that define the
-available printers, classes, and services: The scheduler reads three configuration files that define the
+ available printers, classes, and services: The classes.conf file consists of 1 or more lines of ASCII text.
- Comment lines start with the pound ("#") character. Each non-blank line starts with the name of a configuration
-directive followed by its value. The following directives are
-understood:
+ The classes.conf file consists of 1 or more lines of ASCII text.
+ Comment lines start with the pound ("#") character. Each non-blank line starts with the name of a configuration directive
+ followed by its value. The following directives are understood:
EMail: info@arsoft.com
-
diff --git a/LICENSE.txt b/LICENSE.txt
index e05c045686..a28160c957 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -17,12 +17,12 @@ General Public License ("GPL") and GNU Library General Public License
The GNU LGPL applies to the CUPS API library, located in the "cups"
subdirectory of the CUPS source distribution and in the "/usr/include/cups"
-directory and "libcups.a", "libcups.sl", or "libcups.so" files in the binary
-distributions.
+directory and "libcups.a", "libcups_s.a", "libcups.sl", or "libcups.so"
+files in the binary distributions.
The GNU GPL applies to the remainder of the CUPS distribution, including the
"pstoraster" filter which is based upon GNU Ghostscript 5.50 and the
-"pdftops" filter which is based upon Xpdf 0.90.
+"pdftops" filter which is based upon Xpdf 0.93a.
For those not familiar with the GNU GPL, the license basically allows you
to:
@@ -75,7 +75,7 @@ contact:
Fax: +1.415.492.9862
EMail: info@arsoft.com
-The "pdftops" filter is based on the Xpdf 0.90 software. For binary
+The "pdftops" filter is based on the Xpdf 0.93a software. For binary
distribution licensing of this software, please contact:
Derek B. Noonburg
diff --git a/Makedefs.in b/Makedefs.in
index 8b5bd4d221..731d6ad4ea 100644
--- a/Makedefs.in
+++ b/Makedefs.in
@@ -1,5 +1,5 @@
#
-# "$Id: Makedefs.in,v 1.36.2.1 2001/05/13 18:37:58 mike Exp $"
+# "$Id: Makedefs.in,v 1.36.2.2 2001/12/26 16:52:05 mike Exp $"
#
# Common makefile definitions for the Common UNIX Printing System (CUPS).
#
@@ -29,14 +29,12 @@
AR = @AR@
AWK = @AWK@
CC = @LIBTOOL@ @CC@
-CHMOD = @CHMOD@
-CP = @CP@
CXX = @LIBTOOL@ @CXX@
DSO = @DSO@
HTMLDOC = @HTMLDOC@
+INSTALL = @INSTALL@
LIBTOOL = @LIBTOOL@
LN = /bin/ln -sf
-MKDIR = @MKDIR@ -p
MV = @MV@
NROFF = @NROFF@
RANLIB = @RANLIB@
@@ -48,12 +46,19 @@ SHELL = /bin/sh
# Installation programs...
#
-INSTALL_BIN = $(LIBTOOL) $(CP)
-INSTALL_DATA = $(CP)
-INSTALL_LIB = $(LIBTOOL) $(CP)
-INSTALL_MAN = $(CP)
-INSTALL_SCRIPT = $(CP)
-INSTALL_SYSV = @INSTALL_SYSV@
+INSTALL_BIN = $(LIBTOOL) $(INSTALL) -m 755 -s
+INSTALL_DATA = $(INSTALL) -m 644
+INSTALL_DIR = $(INSTALL) -d
+INSTALL_LIB = $(LIBTOOL) $(INSTALL) -m 755
+INSTALL_MAN = $(INSTALL) -m 644
+INSTALL_SCRIPT = $(INSTALL) -m 755
+
+#
+# Default user and group for the scheduler...
+#
+
+CUPS_USER = @CUPS_USER@
+CUPS_GROUP = @CUPS_GROUP@
#
# Libraries...
@@ -64,6 +69,7 @@ LIBCUPSIMAGE = @LIBCUPSIMAGE@
LIBJPEG = @LIBJPEG@
LIBMALLOC = @LIBMALLOC@
LIBPNG = @LIBPNG@
+LIBSLP = @LIBSLP@
LIBTIFF = @LIBTIFF@
LIBZ = @LIBZ@
@@ -75,7 +81,7 @@ LIBZ = @LIBZ@
# extra debug info)
#
-ARFLAGS = crvs
+ARFLAGS = @ARFLAGS@
CFLAGS = @CFLAGS@ -I.. $(OPTIONS)
CXXFLAGS = @CXXFLAGS@ -I.. $(OPTIONS)
DSOFLAGS = @DSOFLAGS@
@@ -88,6 +94,7 @@ LIBS = $(LINKCUPS) $(NETLIBS) @LIBS@
NETLIBS = @NETLIBS@
OPTIM = @OPTIM@
OPTIONS =
+PAMLIBS = @PAMLIBS@
SSLLIBS = @SSLLIBS@
#
@@ -119,41 +126,44 @@ srcdir = @srcdir@
sysconfdir = @sysconfdir@
top_srcdir = @top_srcdir@
-AMANDIR = @AMANDIR@
-BINDIR = @bindir@
-DATADIR = @CUPS_DATADIR@
-DOCDIR = @CUPS_DOCROOT@
-INCLUDEDIR = $(includedir)
+AMANDIR = $(BUILDROOT)@AMANDIR@
+BINDIR = $(BUILDROOT)@bindir@
+DATADIR = $(BUILDROOT)@CUPS_DATADIR@
+DOCDIR = $(BUILDROOT)@CUPS_DOCROOT@
+INCLUDEDIR = $(BUILDROOT)$(includedir)
INITDIR = @INITDIR@
INITDDIR = @INITDDIR@
-LIBDIR = $(libdir)
-LOCALEDIR = @CUPS_LOCALEDIR@
-LOGDIR = @CUPS_LOGDIR@
-MANDIR = @mandir@
-PAMDIR = @PAMDIR@
-REQUESTS = @CUPS_REQUESTS@
-SBINDIR = @sbindir@
-SERVERBIN = @CUPS_SERVERBIN@
-SERVERROOT = @CUPS_SERVERROOT@
+LIBDIR = $(BUILDROOT)$(libdir)
+LOCALEDIR = $(BUILDROOT)@CUPS_LOCALEDIR@
+LOGDIR = $(BUILDROOT)@CUPS_LOGDIR@
+MANDIR = $(BUILDROOT)@mandir@
+PAMDIR = $(BUILDROOT)@PAMDIR@
+PMANDIR = $(BUILDROOT)@PMANDIR@
+REQUESTS = $(BUILDROOT)@CUPS_REQUESTS@
+SBINDIR = $(BUILDROOT)@sbindir@
+SERVERBIN = $(BUILDROOT)@CUPS_SERVERBIN@
+SERVERROOT = $(BUILDROOT)@CUPS_SERVERROOT@
CAT1EXT = @CAT1EXT@
+CAT3EXT = @CAT3EXT@
CAT5EXT = @CAT5EXT@
CAT8EXT = @CAT8EXT@
MAN8EXT = @MAN8EXT@
+MAN8DIR = @MAN8DIR@
#
# Rules...
#
.SILENT:
-.SUFFIXES: .a .c .cxx .h .man .o .0 .1 .1m .5 .8 .z
+.SUFFIXES: .a .c .cxx .h .man .o .0 .1 .1m .3 .5 .8 .z
.c.o:
echo Compiling $<...
$(CC) $(OPTIM) $(CFLAGS) -c $<
.cxx.o:
echo Compiling $<...
$(CXX) $(OPTIM) $(CXXFLAGS) -c $<
-.man.0 .man.1 .man.1m .man.5 .man.8:
+.man.0 .man.1 .man.1m .man.3 .man.5 .man.8:
echo Formatting $<...
$(RM) $@
$(NROFF) -man $< >$@
@@ -165,5 +175,5 @@ MAN8EXT = @MAN8EXT@
$(MV) t.z $@
#
-# End of "$Id: Makedefs.in,v 1.36.2.1 2001/05/13 18:37:58 mike Exp $"
+# End of "$Id: Makedefs.in,v 1.36.2.2 2001/12/26 16:52:05 mike Exp $"
#
diff --git a/Makefile b/Makefile
index db0cfa236b..b40afe2b93 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.31.2.1 2001/05/13 18:37:58 mike Exp $"
+# "$Id: Makefile,v 1.31.2.2 2001/12/26 16:52:05 mike Exp $"
#
# Top-level Makefile for the Common UNIX Printing System (CUPS).
#
@@ -74,30 +74,32 @@ install:
(cd ppd; $(MAKE) $(MFLAGS) install)
echo Installing in templates...
(cd templates; $(MAKE) $(MFLAGS) install)
+ echo Installing cups-config script...
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_SCRIPT) cups-config $(BINDIR)/cups-config
echo Installing startup script...
if test "x$(INITDIR)" != "x"; then \
- $(MKDIR) $(prefix)/$(INITDIR)/init.d; \
- $(RM) $(prefix)/$(INITDIR)/init.d/cups; \
- $(INSTALL_SCRIPT) cups.sh $(prefix)/$(INITDIR)/init.d/cups; \
- $(CHMOD) ugo+rx $(prefix)/$(INITDIR)/init.d/cups; \
- $(MKDIR) $(prefix)/$(INITDIR)/rc0.d; \
- $(RM) $(prefix)/$(INITDIR)/rc0.d/K00cups; \
- ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc0.d/K00cups; \
- $(MKDIR) $(prefix)/$(INITDIR)/rc2.d; \
- $(RM) $(prefix)/$(INITDIR)/rc2.d/S99cups; \
- ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc2.d/S99cups; \
- $(MKDIR) $(prefix)/$(INITDIR)/rc3.d; \
- $(RM) $(prefix)/$(INITDIR)/rc3.d/S99cups; \
- ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc3.d/S99cups; \
- $(MKDIR) $(prefix)/$(INITDIR)/rc5.d; \
- $(RM) $(prefix)/$(INITDIR)/rc5.d/S99cups; \
- ln -s $(INITDDIR)/cups $(prefix)/$(INITDIR)/rc5.d/S99cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/init.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/init.d/cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc0.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc0.d/K00cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc2.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc2.d/S99cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc3.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc3.d/S99cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDIR)/rc5.d; \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDIR)/rc5.d/S99cups; \
fi
if test "x$(INITDIR)" = "x" -a "x$(INITDDIR)" != "x"; then \
- $(MKDIR) $(prefix)/$(INITDDIR); \
- $(RM) $(prefix)/$(INITDDIR)/cups; \
- $(INSTALL_SCRIPT) cups.sh $(prefix)/$(INITDDIR)/cups; \
- $(CHMOD) ugo+rx $(prefix)/$(INITDDIR)/cups; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDDIR); \
+ if test "$(INITDDIR)" = "/System/Library/StartupItems/CUPS"; then \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDDIR)/CUPS; \
+ $(INSTALL_DATA) cups.plist $(BUILDROOT)$(INITDDIR)/StartupParameters.plist; \
+ $(INSTALL_DIR) $(BUILDROOT)$(INITDDIR)/Resources/English.lproj; \
+ $(INSTALL_DATA) cups.strings $(BUILDROOT)$(INITDDIR)/Resources/English.lproj/Localizable.strings; \
+ else \
+ $(INSTALL_SCRIPT) cups.sh $(BUILDROOT)$(INITDDIR)/cups; \
+ fi \
fi
@@ -114,15 +116,13 @@ test: all
# Make software distributions using EPM (http://www.easysw.com/epm)...
#
-EPMFLAGS = -v \
- AMANDIR=$(AMANDIR) \
- BINDIR=$(BINDIR) DATADIR=$(DATADIR) \
- DOCDIR=$(DOCDIR) INCLUDEDIR=$(INCLUDEDIR) \
- LIBDIR=$(LIBDIR) LOCALEDIR=$(LOCALEDIR) \
- LOGDIR=$(LOGDIR) MANDIR=$(MANDIR) \
- PAMDIR=$(PAMDIR) REQUESTS=$(REQUESTS) \
- SBINDIR=$(SBINDIR) SERVERBIN=$(SERVERBIN) \
- SERVERROOT=$(SERVERROOT)
+EPMFLAGS = -v
+
+aix:
+ epm $(EPMFLAGS) -f aix cups
+
+bsd:
+ epm $(EPMFLAGS) -f bsd cups
epm:
epm $(EPMFLAGS) cups
@@ -143,5 +143,5 @@ tardist:
epm $(EPMFLAGS) -f tardist cups
#
-# End of "$Id: Makefile,v 1.31.2.1 2001/05/13 18:37:58 mike Exp $".
+# End of "$Id: Makefile,v 1.31.2.2 2001/12/26 16:52:05 mike Exp $".
#
diff --git a/README.txt b/README.txt
index 1dad6ea499..1a245aeea7 100644
--- a/README.txt
+++ b/README.txt
@@ -1,4 +1,4 @@
-README - CUPS v1.1.7 - 05/01/2001
+README - CUPS v1.2.0 - 12/26/2001
---------------------------------
Looking for compile instructions? Read the file "INSTALL.txt"
@@ -27,8 +27,8 @@ that are used to support non-PostScript printers. Sample
drivers for HP and EPSON printers are included that use these
filters.
-Drivers for over 2300 printers are provided with our ESP Print
-Pro software, available at:
+Drivers for thousands of printers are provided with our ESP
+Print Pro software, available at:
http://www.easysw.com/printpro
@@ -55,7 +55,8 @@ SOFTWARE REQUIREMENTS
The following operating system software is required to install
one of the binary distributions from Easy Software Products:
- - Digital UNIX (aka OSF1 aka Compaq Tru64 UNIX) 4.0 or higher
+ - AIX 4.3 or higher
+ - Compaq Tru64 UNIX (aka OSF1 aka Digital UNIX) 4.0 or higher
- HP-UX 10.20 or higher
- IRIX 5.3 or higher
- Linux 2.0 with glibc2 or higher
@@ -188,14 +189,20 @@ the following commands:
Similarly, for the other sample drivers you can use:
- Driver PPD File
- -------------------------- ------------
- HP DeskJet Series deskjet.ppd
- HP LaserJet Series laserjet.ppd
- EPSON Stylus Color Series stcolor.ppd
- EPSON Stylus Photo Series stphoto.ppd
- EPSON 9-pin Series epson9.ppd
- EPSON 24-pin Series epson24.ppd
+ Driver PPD File
+ ----------------------------- ------------
+ Dymo Label Printers dymo.ppd
+ EPSON Stylus Color Series stcolor.ppd
+ EPSON Stylus Photo Series stphoto.ppd
+ EPSON Stylus New Color Series stcolor2.ppd
+ EPSON Stylus New Photo Series stphoto2.ppd
+ EPSON 9-pin Series epson9.ppd
+ EPSON 24-pin Series epson24.ppd
+ HP DeskJet Series deskjet.ppd
+ HP New DeskJet Series deskjet2.ppd
+ HP LaserJet Series laserjet.ppd
+ OKIDATA 9-Pin Series okidata9.ppd
+ OKIDATA 24-Pin Series okidat24.ppd
These sample drivers provide basic printing capabilities, but
generally do not exercise the full potential of the printers or
@@ -246,8 +253,8 @@ The PostScript RIP software (pstoraster) is based on the GNU
Ghostscript 5.50 core, Copyright 1986-1998 by Aladdin
Enterprises.
-The PDF filter (pdftops) is based on the Xpdf 0.90 software,
-Copyright 1996-1999 by Derek B. Noonburg.
+The PDF filter (pdftops) is based on the Xpdf 0.92 software,
+Copyright 1996-2001 by Derek B. Noonburg.
This software is based in part on the work of the Independent
JPEG Group.
diff --git a/backend/Makefile b/backend/Makefile
index 6152f31f48..fee32117af 100644
--- a/backend/Makefile
+++ b/backend/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.25.2.1 2001/04/02 19:51:42 mike Exp $"
+# "$Id: Makefile,v 1.25.2.2 2001/12/26 16:52:06 mike Exp $"
#
# Backend makefile for the Common UNIX Printing System (CUPS).
#
@@ -49,10 +49,10 @@ clean:
#
install:
- -$(MKDIR) $(SERVERBIN)/backend
- $(CHMOD) ugo+rx $(SERVERBIN)
- $(CHMOD) ugo+rx $(SERVERBIN)/backend
- $(INSTALL_BIN) $(BACKENDS) $(SERVERBIN)/backend
+ $(INSTALL_DIR) $(SERVERBIN)/backend
+ for file in $(BACKENDS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/backend; \
+ done
$(RM) $(SERVERBIN)/backend/http
$(LN) ipp $(SERVERBIN)/backend/http
@@ -139,5 +139,5 @@ usb.o: ../cups/cups.h
$(OBJS): ../config.h ../Makedefs
#
-# End of "$Id: Makefile,v 1.25.2.1 2001/04/02 19:51:42 mike Exp $".
+# End of "$Id: Makefile,v 1.25.2.2 2001/12/26 16:52:06 mike Exp $".
#
diff --git a/backend/ipp.c b/backend/ipp.c
index 7c10ea60f8..6e29cdd209 100644
--- a/backend/ipp.c
+++ b/backend/ipp.c
@@ -1,5 +1,5 @@
/*
- * "$Id: ipp.c,v 1.38.2.1 2001/05/13 18:37:59 mike Exp $"
+ * "$Id: ipp.c,v 1.38.2.2 2001/12/26 16:52:06 mike Exp $"
*
* IPP backend for the Common UNIX Printing System (CUPS).
*
@@ -408,13 +408,15 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri);
- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
- NULL, argv[2]);
+ if (argv[2][0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+ NULL, argv[2]);
fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]);
- ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
- argv[3]);
+ if (argv[3][0])
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
+ argv[3]);
fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]);
@@ -425,7 +427,12 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
options = NULL;
num_options = cupsParseOptions(argv[5], 0, &options);
- if ((content_type = getenv("CONTENT_TYPE")) != NULL && format_sup != NULL)
+ if (argc > 6)
+ content_type = getenv("CONTENT_TYPE");
+ else
+ content_type = "application/vnd.cups-raw";
+
+ if (content_type != NULL && format_sup != NULL)
{
for (i = 0; i < format_sup->num_values; i ++)
if (strcasecmp(content_type, format_sup->values[i].string.text) == 0)
@@ -436,11 +443,24 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
num_options, &options);
}
- cupsEncodeOptions(request, num_options, options);
+ if (copies_sup)
+ {
+ /*
+ * Only send options if the destination printer supports the copies
+ * attribute. This is a hack for the HP JetDirect implementation of
+ * IPP, which does not accept extension attributes and incorrectly
+ * reports a client-error-bad-request error instead of the
+ * successful-ok-unsupported-attributes status. In short, at least
+ * some HP implementations of IPP are non-compliant.
+ */
+
+ cupsEncodeOptions(request, num_options, options);
+ ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies",
+ atoi(argv[4]));
+ }
+
cupsFreeOptions(num_options, options);
- if (copies_sup)
- ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", atoi(argv[4]));
/*
* Do the request...
@@ -453,6 +473,8 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
if (ipp_status > IPP_OK_CONFLICT)
{
+ job_id = 0;
+
if (ipp_status == IPP_SERVICE_UNAVAILABLE ||
ipp_status == IPP_PRINTER_BUSY)
{
@@ -478,7 +500,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
if (response)
ippDelete(response);
- if (ipp_status <= IPP_OK_CONFLICT)
+ if (ipp_status <= IPP_OK_CONFLICT && argc > 6)
{
fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1);
copies --;
@@ -558,10 +580,11 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
else if ((job_state = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL)
{
/*
- * Stop polling if the job is finished...
+ * Stop polling if the job is finished or pending-held...
*/
- if (job_state->values[0].integer > IPP_JOB_PROCESSING)
+ if (job_state->values[0].integer > IPP_JOB_PROCESSING ||
+ job_state->values[0].integer == IPP_JOB_HELD)
{
ippDelete(response);
break;
@@ -600,7 +623,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
*/
if (ipp_status <= IPP_OK_CONFLICT)
- fputs("INFO: " CUPS_SVERSION " is ready to print.\n", stderr);
+ fputs("INFO: Ready to print.\n", stderr);
return (ipp_status > IPP_OK_CONFLICT);
}
@@ -620,5 +643,5 @@ password_cb(const char *prompt) /* I - Prompt (not used) */
/*
- * End of "$Id: ipp.c,v 1.38.2.1 2001/05/13 18:37:59 mike Exp $".
+ * End of "$Id: ipp.c,v 1.38.2.2 2001/12/26 16:52:06 mike Exp $".
*/
diff --git a/backend/lpd.c b/backend/lpd.c
index 5c4ce28258..e4f405244f 100644
--- a/backend/lpd.c
+++ b/backend/lpd.c
@@ -1,5 +1,5 @@
/*
- * "$Id: lpd.c,v 1.28 2001/03/08 15:13:13 mike Exp $"
+ * "$Id: lpd.c,v 1.28.2.1 2001/12/26 16:52:06 mike Exp $"
*
* Line Printer Daemon backend for the Common UNIX Printing System (CUPS).
*
@@ -398,7 +398,7 @@ lpd_queue(char *hostname, /* I - Host to connect to */
* First try to reserve a port for this connection...
*/
- if ((hostaddr = gethostbyname(hostname)) == NULL)
+ if ((hostaddr = httpGetHostByName(hostname)) == NULL)
{
fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s",
hostname, strerror(errno));
@@ -669,5 +669,5 @@ lpd_write(int lpd_fd, /* I - LPD socket */
/*
- * End of "$Id: lpd.c,v 1.28 2001/03/08 15:13:13 mike Exp $".
+ * End of "$Id: lpd.c,v 1.28.2.1 2001/12/26 16:52:06 mike Exp $".
*/
diff --git a/backend/parallel.c b/backend/parallel.c
index b8474a4cf4..a876da9158 100644
--- a/backend/parallel.c
+++ b/backend/parallel.c
@@ -1,5 +1,5 @@
/*
- * "$Id: parallel.c,v 1.29 2001/03/23 13:58:17 mike Exp $"
+ * "$Id: parallel.c,v 1.29.2.1 2001/12/26 16:52:07 mike Exp $"
*
* Parallel port backend for the Common UNIX Printing System (CUPS).
*
@@ -604,11 +604,26 @@ list_devices(void)
if ((fd = open(device, O_WRONLY)) >= 0)
{
close(fd);
- printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
+ printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (interrupt-driven)\"\n", device, i + 1);
}
sprintf(device, "/dev/lpa%d", i);
if ((fd = open(device, O_WRONLY)) >= 0)
+ {
+ close(fd);
+ printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d (polled)\"\n", device, i + 1);
+ }
+ }
+#elif defined(_AIX)
+ int i; /* Looping var */
+ int fd; /* File descriptor */
+ char device[255]; /* Device filename */
+
+
+ for (i = 0; i < 8; i ++)
+ {
+ sprintf(device, "/dev/lp%d", i);
+ if ((fd = open(device, O_WRONLY)) >= 0)
{
close(fd);
printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1);
@@ -619,5 +634,5 @@ list_devices(void)
/*
- * End of "$Id: parallel.c,v 1.29 2001/03/23 13:58:17 mike Exp $".
+ * End of "$Id: parallel.c,v 1.29.2.1 2001/12/26 16:52:07 mike Exp $".
*/
diff --git a/backend/serial.c b/backend/serial.c
index 192bbc2cdd..050a1f8628 100644
--- a/backend/serial.c
+++ b/backend/serial.c
@@ -1,5 +1,5 @@
/*
- * "$Id: serial.c,v 1.32 2001/03/13 14:05:35 mike Exp $"
+ * "$Id: serial.c,v 1.32.2.1 2001/12/26 16:52:07 mike Exp $"
*
* Serial port backend for the Common UNIX Printing System (CUPS).
*
@@ -189,7 +189,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
do
{
- if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL)) == -1)
+ if ((fd = open(resource, O_WRONLY | O_NOCTTY | O_EXCL | O_NDELAY)) == -1)
{
if (errno == EBUSY)
{
@@ -212,8 +212,9 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
tcgetattr(fd, &opts);
opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */
+ opts.c_oflag &= ~OPOST; /* Don't post-process */
- bufsize = 480; /* 9600 baud / 10 bits/char / 2Hz */
+ bufsize = 96; /* 9600 baud / 10 bits/char / 10Hz */
dtrdsr = 0; /* No dtr/dsr flow control */
if (options != NULL)
@@ -255,7 +256,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
* Set the baud rate...
*/
- bufsize = atoi(value) / 20;
+ bufsize = atoi(value) / 100;
#if B19200 == 19200
cfsetispeed(&opts, atoi(value));
@@ -378,6 +379,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
}
tcsetattr(fd, TCSANOW, &opts);
+ fcntl(fd, F_SETFL, 0);
/*
* Now that we are "connected" to the port, ignore SIGTERM so that we
@@ -476,7 +478,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
}
/*
- * Close the socket connection and input file and return...
+ * Close the serial port and input file and return...
*/
close(fd);
@@ -852,5 +854,5 @@ list_devices(void)
/*
- * End of "$Id: serial.c,v 1.32 2001/03/13 14:05:35 mike Exp $".
+ * End of "$Id: serial.c,v 1.32.2.1 2001/12/26 16:52:07 mike Exp $".
*/
diff --git a/backend/socket.c b/backend/socket.c
index e48fe08c86..115296bb0a 100644
--- a/backend/socket.c
+++ b/backend/socket.c
@@ -1,5 +1,5 @@
/*
- * "$Id: socket.c,v 1.17.2.1 2001/05/13 18:37:59 mike Exp $"
+ * "$Id: socket.c,v 1.17.2.2 2001/12/26 16:52:07 mike Exp $"
*
* AppSocket backend for the Common UNIX Printing System (CUPS).
*
@@ -146,7 +146,7 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
* Then try to connect to the remote host...
*/
- if ((hostaddr = gethostbyname(hostname)) == NULL)
+ if ((hostaddr = httpGetHostByName(hostname)) == NULL)
{
fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n",
hostname, strerror(errno));
@@ -332,12 +332,12 @@ main(int argc, /* I - Number of command-line arguments (6 or 7) */
if (fp != stdin)
fclose(fp);
- fputs("INFO: " CUPS_SVERSION " is ready to print.\n", stderr);
+ fputs("INFO: Ready to print.\n", stderr);
return (0);
}
/*
- * End of "$Id: socket.c,v 1.17.2.1 2001/05/13 18:37:59 mike Exp $".
+ * End of "$Id: socket.c,v 1.17.2.2 2001/12/26 16:52:07 mike Exp $".
*/
diff --git a/backend/usb.c b/backend/usb.c
index c3ecc700bc..3d6ea82ae2 100644
--- a/backend/usb.c
+++ b/backend/usb.c
@@ -1,5 +1,5 @@
/*
- * "$Id: usb.c,v 1.18 2001/02/08 18:46:00 mike Exp $"
+ * "$Id: usb.c,v 1.18.2.1 2001/12/26 16:52:07 mike Exp $"
*
* USB port backend for the Common UNIX Printing System (CUPS).
*
@@ -363,35 +363,55 @@ list_devices(void)
}
fclose(probe);
+
+ /*
+ * Write empty device listings for unused USB devices...
+ */
+
+ for (; i < 16; i ++)
+ {
+ sprintf(device, "/dev/usb/lp%d", i);
+
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usb/usblp%d", i);
+
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usblp%d", i);
+
+ if (access(device, 0))
+ continue;
+ }
+ }
+
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
+ }
}
else
{
/*
- * Just probe manually for USB devices...
+ * Just check manually for USB devices...
*/
- for (i = 0; i < 8; i ++)
+ for (i = 0; i < 16; i ++)
{
sprintf(device, "/dev/usb/lp%d", i);
- if ((fd = open(device, O_WRONLY)) >= 0)
- {
- close(fd);
- printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
- }
- sprintf(device, "/dev/usb/usblp%d", i);
- if ((fd = open(device, O_WRONLY)) >= 0)
+ if (access(device, 0))
{
- close(fd);
- printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
- }
+ sprintf(device, "/dev/usb/usblp%d", i);
- sprintf(device, "/dev/usblp%d", i);
- if ((fd = open(device, O_WRONLY)) >= 0)
- {
- close(fd);
- printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
+ if (access(device, 0))
+ {
+ sprintf(device, "/dev/usblp%d", i);
+
+ if (access(device, 0))
+ continue;
+ }
}
+
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
}
}
#elif defined(__sgi)
@@ -400,38 +420,30 @@ list_devices(void)
#elif defined(__osf)
#elif defined(__FreeBSD__)
int i; /* Looping var */
- int fd; /* File descriptor */
char device[255]; /* Device filename */
for (i = 0; i < 3; i ++)
{
sprintf(device, "/dev/unlpt%d", i);
- if ((fd = open(device, O_WRONLY)) >= 0)
- {
- close(fd);
- printf("direct usb:%s \"Unknown\" \"USB Port #%d\"\n", device, i + 1);
- }
+ if (!access(device, 0))
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
}
#elif defined(__NetBSD__) || defined(__OpenBSD__)
int i; /* Looping var */
- int fd; /* File descriptor */
char device[255]; /* Device filename */
for (i = 0; i < 3; i ++)
{
sprintf(device, "/dev/ulpt%d", i);
- if ((fd = open(device, O_WRONLY)) >= 0)
- {
- close(fd);
- printf("direct usb:%s \"Unknown\" \"USB Port #%d\"\n", device, i + 1);
- }
+ if (!access(device, 0))
+ printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1);
}
#endif
}
/*
- * End of "$Id: usb.c,v 1.18 2001/02/08 18:46:00 mike Exp $".
+ * End of "$Id: usb.c,v 1.18.2.1 2001/12/26 16:52:07 mike Exp $".
*/
diff --git a/berkeley/Makefile b/berkeley/Makefile
index ad830e109b..8ba055ac1a 100644
--- a/berkeley/Makefile
+++ b/berkeley/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.13 2001/01/22 15:03:20 mike Exp $"
+# "$Id: Makefile,v 1.13.2.1 2001/12/26 16:52:07 mike Exp $"
#
# Berkeley commands makefile for the Common UNIX Printing System (CUPS).
#
@@ -48,11 +48,11 @@ clean:
#
install:
- -$(MKDIR) $(BINDIR)
- $(CHMOD) ugo+rx $(BINDIR)
- $(INSTALL_BIN) lpq lpr lprm $(BINDIR)
- -$(MKDIR) $(SBINDIR)
- $(CHMOD) ugo+rx $(SBINDIR)
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_BIN) lpq $(BINDIR)
+ $(INSTALL_BIN) lpr $(BINDIR)
+ $(INSTALL_BIN) lprm $(BINDIR)
+ $(INSTALL_DIR) $(SBINDIR)
$(INSTALL_BIN) lpc $(SBINDIR)
@@ -101,5 +101,5 @@ lprm.o: ../cups/cups.h ../Makedefs
#
-# End of "$Id: Makefile,v 1.13 2001/01/22 15:03:20 mike Exp $".
+# End of "$Id: Makefile,v 1.13.2.1 2001/12/26 16:52:07 mike Exp $".
#
diff --git a/berkeley/lpq.c b/berkeley/lpq.c
index cae40a4d31..2de3622177 100644
--- a/berkeley/lpq.c
+++ b/berkeley/lpq.c
@@ -1,5 +1,5 @@
/*
- * "$Id: lpq.c,v 1.17.2.1 2001/05/13 18:38:00 mike Exp $"
+ * "$Id: lpq.c,v 1.17.2.2 2001/12/26 16:52:08 mike Exp $"
*
* "lpq" command for the Common UNIX Printing System (CUPS).
*
@@ -72,7 +72,9 @@ main(int argc, /* I - Number of command-line arguments */
longstatus; /* Show file details */
int num_dests; /* Number of destinations */
cups_dest_t *dests; /* Destinations */
+#ifdef HAVE_LIBSSL
http_encryption_t encryption; /* Encryption? */
+#endif /* HAVE_LIBSSL */
/*
@@ -536,5 +538,5 @@ show_printer(http_t *http, /* I - HTTP connection to server */
/*
- * End of "$Id: lpq.c,v 1.17.2.1 2001/05/13 18:38:00 mike Exp $".
+ * End of "$Id: lpq.c,v 1.17.2.2 2001/12/26 16:52:08 mike Exp $".
*/
diff --git a/berkeley/lpr.c b/berkeley/lpr.c
index 949a9f3cbc..d25b7c35b3 100644
--- a/berkeley/lpr.c
+++ b/berkeley/lpr.c
@@ -1,5 +1,5 @@
/*
- * "$Id: lpr.c,v 1.20.2.1 2001/05/13 18:38:00 mike Exp $"
+ * "$Id: lpr.c,v 1.20.2.2 2001/12/26 16:52:08 mike Exp $"
*
* "lpr" command for the Common UNIX Printing System (CUPS).
*
@@ -366,7 +366,7 @@ main(int argc, /* I - Number of command-line arguments */
return (1);
}
- while ((i = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ while ((i = read(0, buffer, sizeof(buffer))) > 0)
write(temp, buffer, i);
i = lseek(temp, 0, SEEK_CUR);
@@ -421,5 +421,5 @@ sighandler(int s) /* I - Signal number */
/*
- * End of "$Id: lpr.c,v 1.20.2.1 2001/05/13 18:38:00 mike Exp $".
+ * End of "$Id: lpr.c,v 1.20.2.2 2001/12/26 16:52:08 mike Exp $".
*/
diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile
index 7a4e487293..ca74ac487a 100644
--- a/cgi-bin/Makefile
+++ b/cgi-bin/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.15 2001/02/21 17:01:16 mike Exp $"
+# "$Id: Makefile,v 1.15.2.1 2001/12/26 16:52:08 mike Exp $"
#
# CGI makefile for the Common UNIX Printing System (CUPS).
#
@@ -50,10 +50,10 @@ clean:
#
install:
- -$(MKDIR) $(SERVERBIN)/cgi-bin
- $(CHMOD) ugo+rx $(SERVERBIN)
- $(CHMOD) ugo+rx $(SERVERBIN)/cgi-bin
- $(INSTALL_BIN) $(CGIS) $(SERVERBIN)/cgi-bin
+ $(INSTALL_DIR) $(SERVERBIN)/cgi-bin
+ for file in $(CGIS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/cgi-bin; \
+ done
#
@@ -117,5 +117,5 @@ $(OBJS): ../Makedefs
#
-# End of "$Id: Makefile,v 1.15 2001/02/21 17:01:16 mike Exp $".
+# End of "$Id: Makefile,v 1.15.2.1 2001/12/26 16:52:08 mike Exp $".
#
diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c
index bd4fc28eb6..781a800973 100644
--- a/cgi-bin/admin.c
+++ b/cgi-bin/admin.c
@@ -1,5 +1,5 @@
/*
- * "$Id: admin.c,v 1.22.2.1 2001/05/13 18:38:01 mike Exp $"
+ * "$Id: admin.c,v 1.22.2.2 2001/12/26 16:52:08 mike Exp $"
*
* Administration CGI for the Common UNIX Printing System (CUPS).
*
@@ -549,7 +549,8 @@ do_am_printer(http_t *http, /* I - HTTP connection */
else
oldinfo = NULL;
- if ((name = cgiGetVariable("PRINTER_NAME")) == NULL)
+ if ((name = cgiGetVariable("PRINTER_NAME")) == NULL ||
+ cgiGetVariable("PRINTER_LOCATION") == NULL)
{
if (modify)
{
@@ -1594,5 +1595,5 @@ get_line(char *buf, /* I - Line buffer */
/*
- * End of "$Id: admin.c,v 1.22.2.1 2001/05/13 18:38:01 mike Exp $".
+ * End of "$Id: admin.c,v 1.22.2.2 2001/12/26 16:52:08 mike Exp $".
*/
diff --git a/cgi-bin/template.c b/cgi-bin/template.c
index b95e0f356a..088cbb122d 100644
--- a/cgi-bin/template.c
+++ b/cgi-bin/template.c
@@ -1,5 +1,5 @@
/*
- * "$Id: template.c,v 1.22 2001/01/22 15:03:22 mike Exp $"
+ * "$Id: template.c,v 1.22.2.1 2001/12/26 16:52:09 mike Exp $"
*
* CGI template function.
*
@@ -480,11 +480,13 @@ cgi_puts(const char *s,
{
while (*s)
{
- if (s[0] == '<' && s[1] != '/' && !isalpha(s[1]))
+ if (s[0] == '<')
fputs("<", out);
+ else if (s[0] == '>')
+ fputs(">", out);
else if (*s == '\"')
fputs(""", out);
- else if (s[0] == '&' && isspace(s[1]))
+ else if (s[0] == '&')
fputs("&", out);
else
putc(*s, out);
@@ -495,5 +497,5 @@ cgi_puts(const char *s,
/*
- * End of "$Id: template.c,v 1.22 2001/01/22 15:03:22 mike Exp $".
+ * End of "$Id: template.c,v 1.22.2.1 2001/12/26 16:52:09 mike Exp $".
*/
diff --git a/conf/Makefile b/conf/Makefile
index 47c71ff88b..539626579e 100644
--- a/conf/Makefile
+++ b/conf/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.10 2001/01/22 15:03:23 mike Exp $"
+# "$Id: Makefile,v 1.10.2.1 2001/12/26 16:52:09 mike Exp $"
#
# Configuration file makefile for the Common UNIX Printing System (CUPS).
#
@@ -51,8 +51,7 @@ clean:
#
install:
- -$(MKDIR) $(SERVERROOT)
- $(CHMOD) ugo+rx $(SERVERROOT)
+ $(INSTALL_DIR) $(SERVERROOT)
for file in $(KEEP); do \
if test -r $(SERVERROOT)/$$file ; then \
$(INSTALL_DATA) $$file $(SERVERROOT)/$$file.N ; \
@@ -69,5 +68,5 @@ install:
#
-# End of "$Id: Makefile,v 1.10 2001/01/22 15:03:23 mike Exp $".
+# End of "$Id: Makefile,v 1.10.2.1 2001/12/26 16:52:09 mike Exp $".
#
diff --git a/conf/cupsd.conf b/conf/cupsd.conf
index 462abc1502..e03f97e079 100644
--- a/conf/cupsd.conf
+++ b/conf/cupsd.conf
@@ -1,5 +1,5 @@
#
-# "$Id: cupsd.conf,v 1.32.2.1 2001/04/02 19:51:42 mike Exp $"
+# "$Id: cupsd.conf,v 1.32.2.2 2001/12/26 16:52:09 mike Exp $"
#
# Sample configuration file for the Common UNIX Printing System (CUPS)
# scheduler.
@@ -75,6 +75,7 @@
# Classification: the classification level of the server. If set, this
# classification is displayed on all pages, and raw printing is disabled.
# The default is the empty string.
+#
#Classification classified
#Classification confidential
@@ -82,6 +83,17 @@
#Classification topsecret
#Classification unclassified
+#
+# ClassifyOverride: whether to allow users to override the classification
+# on printouts. If enabled, users can limit banner pages to before or
+# after the job, and can change the classification of a job, but cannot
+# completely eliminate the classification or banners.
+#
+# The default is off.
+#
+
+#ClassifyOverride off
+
#
# DataDir: the root directory for the CUPS data files.
# By default /usr/share/cups.
@@ -184,10 +196,10 @@ LogLevel info
#
# MaxJobs: maximum number of jobs to keep in memory (active and completed.)
-# Default is 0 (no limit.)
+# Default is 500; the value 0 is used for no limit.
#
-#MaxJobs 0
+#MaxJobs 500
#
# Printcap: the name of the printcap file. Default is /etc/printcap.
@@ -370,6 +382,25 @@ Port 631
#Browsing On
+#
+# BrowseProtocols: which protocols to use for browsing. Can be
+# any of the following separated by whitespace and/or commas:
+#
+# all - Use all supported protocols.
+# cups - Use the CUPS browse protocol.
+# slp - Use the SLPv2 protocol.
+#
+# The default is "cups".
+#
+# NOTE: If you choose to use SLPv2, it is *strongly* recommended that
+# you have at least one SLP Directory Agent (DA) on your
+# network. Otherwise, browse updates can take several seconds,
+# during which the scheduler will not response to client
+# requests.
+#
+
+#BrowseProtocols cups
+
#
# BrowseAddress: specifies a broadcast address to be used. By
# default browsing information is not sent!
@@ -494,6 +525,36 @@ Port 631
#ImplicitClasses On
+#
+# ImplicitAnyClasses: whether or not to create "AnyPrinter" implicit
+# classes.
+#
+# When ImplicitAnyClasses is On and a local queue of the same name
+# exists, e.g. "printer", "printer@server1", "printer@server1", then
+# an implicit class called "Anyprinter" is created instead.
+#
+# When ImplicitAnyClasses is Off, implicit classes are not created
+# when there is a local queue of the same name.
+#
+# Disabled by default.
+#
+
+#ImplicitAnyCLasses Off
+
+#
+# HideImplicitMembers: whether or not to show the members of an
+# implicit class.
+#
+# When HideImplicitMembers is On, any remote printers that are
+# part of an implicit class are hidden from the user, who will
+# then only see a single queue even though many queues will be
+# supporting the implicit class.
+#
+# Enabled by default.
+#
+
+#HideImplicitMembers On
+
########
######## Security Options
@@ -654,5 +715,5 @@ Allow From 127.0.0.1
#
-# End of "$Id: cupsd.conf,v 1.32.2.1 2001/04/02 19:51:42 mike Exp $".
+# End of "$Id: cupsd.conf,v 1.32.2.2 2001/12/26 16:52:09 mike Exp $".
#
diff --git a/conf/mime.types b/conf/mime.types
index fadc5aad4b..12dc0c7a31 100644
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -1,5 +1,5 @@
#
-# "$Id: mime.types,v 1.17.2.1 2001/05/13 18:38:02 mike Exp $"
+# "$Id: mime.types,v 1.17.2.2 2001/12/26 16:52:09 mike Exp $"
#
# MIME types file for the Common UNIX Printing System (CUPS).
#
@@ -131,6 +131,7 @@ text/plain txt printable(0,1024)
application/vnd.cups-form string(0,"
- CUPS Configuration Management Plan
+
+CUPS Configuration Management Plan
CUPS-CMP-1.1
Easy Software Products
Copyright 1997-2001, All Rights Reserved
@@ -116,28 +116,28 @@ Copyright 1997-2001, All Rights Reserved
C Software Trouble Report Form
1 Scope
1.1 Identification
- This configuration management plan document provides the guidelines
-for development and maintenance of the Common UNIX Printing System
-("CUPS") Version 1.1 software.
+ This configuration management plan document provides the guidelines for
+ development and maintenance of the Common UNIX Printing System ("CUPS")
+ Version 1.1 software.
1.2 System Overview
-1.3 Document Overview
- This configuration management document is organized into the following
-sections:
+ This configuration management document is organized into the following
+ sections:
2 References
2.1 CUPS Documentation
-
-
+
2.2 Other Documents
-
3 File Management
3.1 Directory Structure
- Each source file shall be placed a sub-directory corresponding to the
-software sub-system it belongs to ("scheduler", "cups", etc.) To remain
-compatible with older UNIX filesystems, directory names shall not
-exceed 16 characters in length.
+ Each source file shall be placed a sub-directory corresponding to the
+ software sub-system it belongs to ("scheduler", "cups", etc.) To remain
+ compatible with older UNIX filesystems, directory names shall not
+ exceed 16 characters in length.
3.2 Source Files
- Source files shall be documented and formatted as described in
-Appendix B, Coding Requirements.
+ Source files shall be documented and formatted as described in Appendix
+ B, Coding Requirements.
3.3 Configuration Management
- Source files shall be placed under the control of the Concurrent
-Versions System ("CVS") software. Source files shall be "checked in"
-with each change so that modifications can be tracked.
-4 Trouble Report Processing
- A Software Trouble Report ("STR") shall be submitted every time a user
-or vendor experiences a problem with the CUPS software. Trouble reports
-are maintained in a database with one of the following states:
+ A Software Trouble Report ("STR") shall be submitted every time a user
+ or vendor experiences a problem with the CUPS software. Trouble reports
+ are maintained in a database with one of the following states:
- Trouble reports shall be processed using the following steps.
+ Trouble reports shall be processed using the following steps.
4.1 Classification
- When a trouble report is received it must be classified at one of the
-following levels:
+ When a trouble report is received it must be classified at one of the
+ following levels:
- The scope of the problem should also be determined as:
+ The scope of the problem should also be determined as:
4.2 Identification
- Once the level and scope of the trouble report is determined the
-software sub-system(s) involved with the problem are determined. This
-may involve additional communication with the user or vendor to isolate
-the problem to a specific cause.
-4.3 Correction
- Corrections are scheduled based upon the severity and complexity of
-the problem. Once all changes have been made, documented, and tested
-successfully a new software release snapshot is generated. Additional
-tests are added as necessary for proper testing of the changes.
+ Corrections are scheduled based upon the severity and complexity of the
+ problem. Once all changes have been made, documented, and tested
+ successfully a new software release snapshot is generated. Additional
+ tests are added as necessary for proper testing of the changes.
4.4 Notification
- The user or vendor is notified when the fix is available or if the
-problem was caused by user error.
+ The user or vendor is notified when the fix is available or if the
+ problem was caused by user error.
5 Software Releases
5.1 Version Numbering
- CUPS uses a three-part version number separated by periods to
-represent the major, minor, and patch release numbers:
+ CUPS uses a three-part version number separated by periods to represent
+ the major, minor, and patch release numbers:
major.minor.patch
1.1.0
- Beta-test releases are indentified by appending the letter B followed
-by the build number:
+ Beta-test releases are indentified by appending the letter B followed
+ by the build number:
major.minor.patchbbuild
1.1.0b1
- A CVS snapshot is generated for every beta and final release and uses
-the version number preceded by the letter "v" and with the decimal
-points replaced by underscores:
+ A CVS snapshot is generated for every beta and final release and uses
+ the version number preceded by the letter "v" and with the decimal
+ points replaced by underscores:
v1_0_0b1
v1_0_0
- Each change that corrects a fault in a software sub-system increments
-the patch release number. If a change affects the software design of
-CUPS then the minor release number will be incremented and the patch
-release number reset to 0. If CUPS is completely redesigned the major
-release number will be incremented and the minor and patch release
-numbers reset to 0:
+ Each change that corrects a fault in a software sub-system increments
+ the patch release number. If a change affects the software design of
+ CUPS then the minor release number will be incremented and the patch
+ release number reset to 0. If CUPS is completely redesigned the major
+ release number will be incremented and the minor and patch release
+ numbers reset to 0:
1.1.0b1 First beta release
@@ -293,82 +293,82 @@ numbers reset to 0:
5.2 Generation
- Software releases shall be generated for each successfully completed
-software trouble report. All object and executable files shall be
-deleted prior to performing a full build to ensure that source files
-are recompiled.
+ Software releases shall be generated for each successfully completed
+ software trouble report. All object and executable files shall be
+ deleted prior to performing a full build to ensure that source files
+ are recompiled.
5.3 Testing
- Software testing shall be conducted according to the CUPS Software
-Test Plan, CUPS-STP-1.1. Failed tests cause STRs to be generated to
-correct the problems found.
+ Software testing shall be conducted according to the CUPS Software Test
+ Plan, CUPS-STP-1.1. Failed tests cause STRs to be generated to correct
+ the problems found.
5.4 Release
- When testing has been completed successfully a new distribution image
-is created from the current CVS code "snapshot". No production release
-shall contain software that has not passed the appropriate software
-tests.
+ When testing has been completed successfully a new distribution image
+ is created from the current CVS code "snapshot". No production release
+ shall contain software that has not passed the appropriate software
+ tests.
A Glossary
A.1 Terms
-
A.2 Acronyms
-
B Coding Requirements
- These coding requirements provide detailed information on source file
-formatting and documentation content. These guidelines shall be applied
-to all C and C++ source files provided with CUPS.
+ These coding requirements provide detailed information on source file
+ formatting and documentation content. These guidelines shall be applied
+ to all C and C++ source files provided with CUPS.
B.1 Source Files
B.1.1 Naming
- All source files names shall be 16 characters or less in length to
-ensure compatibility with older UNIX filesystems. Source files
-containing functions shall have an extension of ".c" for ANSI C and
-".cxx" for C++ source files. All other "include" files shall have an
-extension of ".h".
+ All source files names shall be 16 characters or less in length to
+ ensure compatibility with older UNIX filesystems. Source files
+ containing functions shall have an extension of ".c" for ANSI C and
+ ".cxx" for C++ source files. All other "include" files shall have an
+ extension of ".h".
B.1.2 Documentation
- The top of each source file shall contain a header giving the name of
-the file, the purpose or nature of the source file, the copyright and
-licensing notice, and the functions contained in the file. The file
-name and revision information is provided by the CVS "$Id$" tag:
+ The top of each source file shall contain a header giving the name of
+ the file, the purpose or nature of the source file, the copyright and
+ licensing notice, and the functions contained in the file. The file
+ name and revision information is provided by the CVS "$Id$" tag:
/*
@@ -403,10 +403,10 @@ name and revision information is provided by the CVS "$Id$" tag:
*/
- The bottom of each source file shall contain a trailer giving the name
-of the file using the CVS "$Id$" tag. The primary purpose of this is to
-mark the end of a source file; if the trailer is missing it is possible
-that code has been lost near the end of the file:
+ The bottom of each source file shall contain a trailer giving the name
+ of the file using the CVS "$Id$" tag. The primary purpose of this is to
+ mark the end of a source file; if the trailer is missing it is possible
+ that code has been lost near the end of the file:
/*
@@ -416,17 +416,17 @@ that code has been lost near the end of the file:
B.2 Functions
B.2.1 Naming
- Functions with a global scope shall be capitalized ("DoThis",
-"DoThat", "DoSomethingElse", etc.) The only exception to this rule
-shall be the CUPS interface library functions which may begin with a
-prefix word in lowercase ("cupsDoThis", "cupsDoThat", etc.)
-B.2.2 Documentation
- Each function shall begin with a comment header describing what the
-function does, the possible input limits (if any), and the possible
-output values (if any), and any special information needed:
+ Each function shall begin with a comment header describing what the
+ function does, the possible input limits (if any), and the possible
+ output values (if any), and any special information needed:
/*
@@ -445,12 +445,12 @@ do_this(float x) /* I - Power value (0.0 <= x <= 1.1) */
B.3 Methods
B.3.1 Naming
- Methods shall be in lowercase with underscores between words
-("do_this", "do_that", "do_something_else", etc.)
+ Methods shall be in lowercase with underscores between words
+ ("do_this", "do_that", "do_something_else", etc.)
B.3.2 Documentation
- Each method shall begin with a comment header describing what the
-method does, the possible input limits (if any), and the possible
-output values (if any), and any special information needed:
+ Each method shall begin with a comment header describing what the
+ method does, the possible input limits (if any), and the possible
+ output values (if any), and any special information needed:
/*
@@ -469,19 +469,19 @@ class::do_this(float x) /* I - Power value (0.0 <= x <= 1.0) */
B.4 Variables
B.4.1 Naming
- Variables with a global scope shall be capitalized ("ThisVariable",
-"ThatVariable", "ThisStateVariable", etc.) The only exception to this
-rule shall be the CUPS interface library global variables which must
-begin with the prefix "cups" ("cupsThisVariable", "cupsThatVariable",
-etc.) Global variables shall be replaced by function arguments whenever
-possible.
-B.4.2 Documentation
- Each variable shall be declared on a separate line and shall be
-immediately followed by a comment block describing the variable:
+ Each variable shall be declared on a separate line and shall be
+ immediately followed by a comment block describing the variable:
int this_variable; /* The current state of this */
@@ -490,11 +490,11 @@ int that_variable; /* The current state of that */
B.5 Types
B.5.1 Naming
- All type names shall be lowercase with underscores between words and
-"_t" appended to the end of the name ("this_type_t", "that_type_t",
-etc.)
+ All type names shall be lowercase with underscores between words and
+ "_t" appended to the end of the name ("this_type_t", "that_type_t",
+ etc.)
B.5.2 Documentation
- Each type shall have a comment block immediately before the typedef:
+ Each type shall have a comment block immediately before the typedef:
/*
@@ -505,13 +505,13 @@ typedef int cups_this_type_t;
B.6 Structures
B.6.1 Naming
- All structure names shall be lowercase with underscores between words
-and "_str" appended to the end of the name ("this_struct_str",
-"that_struct_str", etc.)
+ All structure names shall be lowercase with underscores between words
+ and "_str" appended to the end of the name ("this_struct_str",
+ "that_struct_str", etc.)
B.6.2 Documentation
- Each structure shall have a comment block immediately before the
-struct and each member shall be documented in accordance with the
-variable naming policy above:
+ Each structure shall have a comment block immediately before the struct
+ and each member shall be documented in accordance with the variable
+ naming policy above:
/*
@@ -526,12 +526,12 @@ struct cups_this_struct_str
B.7 Classes
B.7.1 Naming
- All class names shall be lowercase with underscores between words
-("this_class", "that_class", etc.)
+ All class names shall be lowercase with underscores between words
+ ("this_class", "that_class", etc.)
B.7.2 Documentation
- Each class shall have a comment block immediately before the class and
-each member shall be documented in accordance with the variable naming
-policy above:
+ Each class shall have a comment block immediately before the class and
+ each member shall be documented in accordance with the variable naming
+ policy above:
/*
@@ -546,14 +546,14 @@ class cups_this_class
B.8 Constants
B.8.1 Naming
- All constant names shall be uppercase with underscored between words
-("THIS_CONSTANT", "THAT_CONSTANT", etc.) Constants defined for the CUPS
-interface library must begin with an uppercase prefix
-("CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", etc.)
-B.8.2 Documentation
- Comment blocks shall immediately follow each constant:
+ Comment blocks shall immediately follow each constant:
enum
@@ -565,8 +565,8 @@ enum
B.9 Code
B.9.1 Documentation
- All source code shall utilize block comments within functions to
-describe the operations being performed by a group of statements:
+ All source code shall utilize block comments within functions to
+ describe the operations being performed by a group of statements:
/*
@@ -593,10 +593,10 @@ do
B.9.2 Style
B.9.2.a Indentation
- All code blocks enclosed by brackets shall begin with the opening
-brace on a new line. The code then follows starting on a new line after
-the brace and is indented 2 spaces. The closing brace is then placed on
-a new line following the code at the original indentation:
+ All code blocks enclosed by brackets shall begin with the opening brace
+ on a new line. The code then follows starting on a new line after the
+ brace and is indented 2 spaces. The closing brace is then placed on a
+ new line following the code at the original indentation:
{
@@ -614,10 +614,9 @@ a new line following the code at the original indentation:
}
- Single-line statements following "do", "else", "for", "if", and
-"while" shall be indented 2 spaces as well. Blocks of code in a
-"switch" block shall be indented 4 spaces after each "case" and
-"default" case:
+ Single-line statements following "do", "else", "for", "if", and "while"
+ shall be indented 2 spaces as well. Blocks of code in a "switch" block
+ shall be indented 4 spaces after each "case" and "default" case:
switch (array[i])
@@ -633,20 +632,20 @@ switch (array[i])
B.9.2.b Spacing
- A space shall follow each reserved word ("if", "while", etc.) Spaces
-shall not be inserted between a function name and the arguments in
-parenthesis.
+ A space shall follow each reserved word ("if", "while", etc.) Spaces
+ shall not be inserted between a function name and the arguments in
+ parenthesis.
B.9.2.c Return Values
- Parenthesis shall surround values returned from a function using
-"return":
+ Parenthesis shall surround values returned from a function using
+ "return":
return (STATE_IDLE);
B.9.2.d Loops
- Whenever convenient loops should count downward to zero to improve
-program performance:
+ Whenever convenient loops should count downward to zero to improve
+ program performance:
for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
@@ -658,19 +657,19 @@ for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
-Summary of Problem:
________________________________________ Problem Severity: __1=RFE
-
__2=Documentation-Error
-
__3=Unable-to-Print-a-File
-
__4=Unable-to-Print-to-a-Printer
+
-Problem Severity: __1=RFE
+
__2=Documentation-Error
+
__3=Unable-to-Print-a-File
+
__4=Unable-to-Print-to-a-Printer
__5=Unable-to-Print-at-All
+Problem Scope: __1=Machine
-__2=Operating-System __3=All Problem Scope: __1=Machine
+ __2=Operating-System __3=All Detailed Description of Problem: ________________________________________
-
________________________________________
-
________________________________________
-
________________________________________
-
________________________________________
+ALIGN="LEFT">________________________________________
+
________________________________________
+
________________________________________
+
________________________________________
+
________________________________________
________________________________________
- CUPS Interface Design Description
+
+CUPS Interface Design Description
CUPS-IDD-1.1
Easy Software Products
Copyright 1997-2001, All Rights Reserved
@@ -91,197 +91,197 @@ Copyright 1997-2001, All Rights Reserved
1 Scope
1.1 Identification
-1.2 System Overview
-1.3 Document Overview
-
-
2 References
2.1 CUPS Documentation
-
-
2.2 Other Documents
-
3 Internal Interfaces
3.1 Character Set Files
-3.1.1 8-Bit Character Set Files
-
charset 8bit
-
first last direction width normal bold italic bold-italic
-
xx yyyy
3.1.2 Unicode Character Set Files
-
charset encoding
-
first last direction width normal bold italic bold-italic
-3.2 Language Files
-
-
-3.3 MIME Files
-3.3.1 mime.types
-
mime-type := super "/" type { SP rule }*
@@ -303,31 +303,31 @@ operator := "+" | [ logical AND ]
"!" [ unary NOT ]
-int
and short
rules match look for
-integers in network byte order (a.k.a. big-endian) with the
-most-significant byte first. int
and short
rules match look for
+ integers in network byte order (a.k.a. big-endian) with the
+ most-significant byte first.3.3.2 mime.convs
-
super/type SP super/type2 SP cost SP program
3.4 Option Files
-/etc/cups/lpoptions
) are loaded first,
-followed by the user option file ($HOME/.lpoptions
).
-Options in the user file replace those defined in the system file for
-the same destination. Each line in the files can be one of the
-following: /etc/cups/lpoptions
) are loaded first,
+ followed by the user option file ($HOME/.lpoptions
).
+ Options in the user file replace those defined in the system file for
+ the same destination. Each line in the files can be one of the
+ following:
Dest name option=value option=value ... option=value
@@ -336,300 +336,295 @@ Default name option=value option=value ... option=value
Default name/instance option=value option=value ... option=value
-3.5 PostScript Printer Description Files
-3.5.1 PPD Specification
-3.5.2 CUPS Extensions to PPD Files
-3.5.2.1 cupsFilter
-
source/type cost program
-3.5.2.2 cupsManualCopies
-3.5.2.3 cupsModelNumber
-3.5.2.4 cupsProfile
-
resolution/type density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22
-Resolution
- or MediaType
attributes defined in the PPD file. Resolution
+ or MediaType
attributes defined in the PPD file.
f(x) = density * xgamma
-3.5.2.5 cupsVersion
-3.6 Scheduler Configuration Files
-
-
3.6.1 classes.conf
-
Directive Description <Class name>
</Class>Surrounds a class definition.
-<DefaultClass name>
-
</Class>Surrounds a class definition for the default
-destination.
-Accepting Specifies whether the class is accepting new
-jobs. May be the names "Yes" or "No".
-AllowUsers Specifies a list of users that are allowed
-to access the class.
-BannerStart Specifies the banner that is printed before
-other files in a job.
-BannerEnd Specifies the banner that is printed after
-other files in a job.
+DenyUsers Specifies a list of users that are not
-allowed to access the class.
</Class>Surrounds a class definition for the default
+ destination.
+
+Accepting Specifies whether the class is accepting new
+ jobs. May be the names "Yes" or "No".
+AllowUsers Specifies a list of users that are allowed to
+ access the class.
+BannerStart Specifies the banner that is printed before
+ other files in a job.
+BannerEnd Specifies the banner that is printed after
+ other files in a job. DenyUsers Specifies a list of users that are not allowed
+ to access the class. Info A textual description of the class.
-Location A textual location of the class.
-Printer Specifies a printer that is a member of the
-class.
-State Specifies the initial state of the class; can be
-"Idle" or "Stopped".
+StateMessage Specifies a textual message for the
-current class state.
+Printer Specifies a printer that is a member of the
+ class.
+State Specifies the initial state of the class; can be
+ "Idle" or "Stopped". StateMessage Specifies a textual message for the current
+ class state.
The cupsd.conf file consists of 1 or more lines of ASCII text. - Comment lines start with the pound ("#") character.
-Each non-blank line starts with the name of a configuration -directive followed by its value. The following directives are -understood: +
The cupsd.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.
+Each non-blank line starts with the name of a configuration directive + followed by its value. The following directives are understood:
Directive | Default | Description |
---|---|---|
AccessLog | access_log | Specifies the location of -the access log file. The special name "syslog" can be used to send -access log information to the system log. |
Allow | - | Allows connections from the specified -host, network, or domain. |
AuthClass | - | Specifies what level of -authentication is required; may be "User", "System", or "Group". |
AuthType | None | Specifies the type of -authentication to perform; may be "None", "Basic", or "Digest". |
BrowseAddress | 255.255.255.255 | Specifies a -broadcast address to send CUPS browsing packets to. |
BrowseAllow | - | Specifies hosts or addresses from -which browsing information should be used. |
BrowseDeny | - | Specifies hosts or addresses from -which browsing information should not be used. |
BrowseInterval | 30 | Specifies the number of -seconds between browsing updates. A browse interval of 0 seconds -disables outgoing packets. |
BrowseOrder | Allow,Deny | Specifies the order of -BrowseAllow and BrowseDeny directive processing; can be "Deny,Allow" -to implicitly deny hosts unless they are allowed by a BrowseAllow -line, or "Allow,Deny" to implicitly allow hosts unless they are denied -by a BrowseDeny line. |
BrowsePoll | - | Specifies a server to poll for -available printers and classes. |
BrowsePort | 631 | Specifies the UDP port number to -use for browse packets. |
BrowseRelay | - | Specifies a source and -destination address for relaying browser information from one subnet -to another. |
BrowseShortNames | yes | Specifies whether or not -to provide short names (without the "@server" part) for remote -printers. |
BrowseTimeout | 300 | Specifies the number of -seconds to wait until remote destinations are removed from the local -destination list. |
Browsing | On | Specifies whether or not printer -and class browsing is enabled; can be "On" or "Off". |
DataDir | /usr/share/cups | Specifies the directory -where CUPS data files are stored. |
DefaultCharset | iso-8859-1 | Specifies the default -character set. |
DefaultLanguage | current locale | Specifies the -default language. |
Deny | - | Refuses connections from the specified -host, network, or domain. |
DocumentRoot | /usr/share/doc/cups | Specifies the -document data root directory. |
ErrorLog | error_log | Specifies the error log file -location. The special name "syslog" can be used to send error log -information to the system log. |
Group | root, sys, system | Specifies the group -name or ID that is used when running external programs. |
HostNameLookups | Off | Specifies whether or not to -perform reverse IP address lookups to get the actual hostname; may be -"On" or "Off". Hostname lookups can significantly degrade the -performance of the CUPS server if one or more DNS servers is not -functioning properly. |
ImplicitClasses | On | Specifies whether or not to -automatically create printer classes when more than one printer or -class of the same name is detected on the network; may be "On" or -"Off". |
KeepAlive | On | Specifies whether or not to use -the HTTP Keep-Alive feature; may be "On" or "Off". |
KeepAliveTimeout | 30 | Specifies the amount of -time to keep the HTTP connection alive before closing it. |
AccessLog | access_log | Specifies the location of + the access log file. The special name "syslog" can be used to send + access log information to the system log. |
Allow | - | Allows connections from the specified + host, network, or domain. |
AuthClass | - | Specifies what level of + authentication is required; may be "User", "System", or "Group". |
AuthType | None | Specifies the type of + authentication to perform; may be "None", "Basic", or "Digest". |
BrowseAddress | 255.255.255.255 | Specifies a + broadcast address to send CUPS browsing packets to. |
BrowseAllow | - | Specifies hosts or addresses from + which browsing information should be used. |
BrowseDeny | - | Specifies hosts or addresses from + which browsing information should not be used. |
BrowseInterval | 30 | Specifies the number of + seconds between browsing updates. A browse interval of 0 seconds + disables outgoing packets. |
BrowseOrder | Allow,Deny | Specifies the order of + BrowseAllow and BrowseDeny directive processing; can be "Deny,Allow" to + implicitly deny hosts unless they are allowed by a BrowseAllow line, or + "Allow,Deny" to implicitly allow hosts unless they are denied by a + BrowseDeny line. |
BrowsePoll | - | Specifies a server to poll for + available printers and classes. |
BrowsePort | 631 | Specifies the UDP port number to + use for browse packets. |
BrowseRelay | - | Specifies a source and destination + address for relaying browser information from one subnet to another. | +
BrowseShortNames | yes | Specifies whether or not to + provide short names (without the "@server" part) for remote printers. | +
BrowseTimeout | 300 | Specifies the number of + seconds to wait until remote destinations are removed from the local + destination list. |
Browsing | On | Specifies whether or not printer and + class browsing is enabled; can be "On" or "Off". |
DataDir | /usr/share/cups | Specifies the directory + where CUPS data files are stored. |
DefaultCharset | iso-8859-1 | Specifies the default + character set. |
DefaultLanguage | current locale | Specifies the + default language. |
Deny | - | Refuses connections from the specified + host, network, or domain. |
DocumentRoot | /usr/share/doc/cups | Specifies the + document data root directory. |
ErrorLog | error_log | Specifies the error log file + location. The special name "syslog" can be used to send error log + information to the system log. |
Group | root, sys, system | Specifies the group name + or ID that is used when running external programs. |
HostNameLookups | Off | Specifies whether or not to + perform reverse IP address lookups to get the actual hostname; may be + "On" or "Off". Hostname lookups can significantly degrade the + performance of the CUPS server if one or more DNS servers is not + functioning properly. |
ImplicitClasses | On | Specifies whether or not to + automatically create printer classes when more than one printer or + class of the same name is detected on the network; may be "On" or + "Off". |
KeepAlive | On | Specifies whether or not to use the + HTTP Keep-Alive feature; may be "On" or "Off". |
KeepAliveTimeout | 30 | Specifies the amount of time + to keep the HTTP connection alive before closing it. |
<Location path>
- </Location> | - | Specifies a location to restrict -access to. |
LogLevel | info | Controls the amount of -information that is logged in the error log file. Can be one of -"debug", "info", "warn", "error", or "none", in decreasing order or -verbosity. |
MaxClients | 100 | Specifies the maximum number of -simultaneous active clients. This value is internally limited to 1/3 -of the total number of available file descriptors. |
MaxLogSize | 0 | Specifies the maximum size of the -access, error, and page log files in bytes. If set to 0 then no -maximum size is set. Log files are rotated automatically when this -size is exceeded. |
MaxRequestSize | 0 | Specifies the maximum size of -HTTP requests in bytes. If set to 0 then there is no maximum. |
Order | Allow,Deny | Specifies the order of Allow -and Deny directive processing; can be "Deny,Allow" to implicitly deny -hosts unless they are allowed by an Allow line, or "Allow,Deny" to -implicitly allow hosts unless they are denied by a Deny line. |
PageLog | page_log | Specifies the location of the -page log file. The special name "syslog" can be used to send page log -information to the system log. |
Port | 631 | Specifies a port number to listen to -for HTTP connections. |
Printcap | /etc/printcap | Specifies the location -of a Berkeley printcap file to update with a list of current printers -and classes. If no filename is supplied then this automatic generation -is disabled. |
RequestRoot | /var/spool/cups | Specifies the -location of request files. |
RIPCache | 8m | Specifies the size of the memory -cache in bytes that is used by RIP filters. |
ServerAdmin | root@ServerName | Specifies the -person to contact with problems. |
ServerName | hostname | Specifies the hostname that -is supplied to HTTP clients. This is also used to determine the -default CUPS server for the CUPS IPP client applications. |
ServerRoot | /etc/cups | Specifies the root -directory for server configuration files. |
SystemGroup | root, sys, system | Specifies the -group name used for System class authentication. |
TempDir | /var/tmp | Specifies the temporary -directory to use. |
Timeout | 300 | The timeout in seconds before -client connections are closed in the middle of a request. |
User | lp | Specifies the user that is used when -running external programs. | - | Specifies a location to restrict + access to. | +
LogLevel | info | Controls the amount of information + that is logged in the error log file. Can be one of "debug", "info", + "warn", "error", or "none", in decreasing order or verbosity. |
MaxClients | 100 | Specifies the maximum number of + simultaneous active clients. This value is internally limited to 1/3 of + the total number of available file descriptors. |
MaxLogSize | 0 | Specifies the maximum size of the + access, error, and page log files in bytes. If set to 0 then no maximum + size is set. Log files are rotated automatically when this size is + exceeded. |
MaxRequestSize | 0 | Specifies the maximum size of + HTTP requests in bytes. If set to 0 then there is no maximum. |
Order | Allow,Deny | Specifies the order of Allow + and Deny directive processing; can be "Deny,Allow" to implicitly deny + hosts unless they are allowed by an Allow line, or "Allow,Deny" to + implicitly allow hosts unless they are denied by a Deny line. |
PageLog | page_log | Specifies the location of the + page log file. The special name "syslog" can be used to send page log + information to the system log. |
Port | 631 | Specifies a port number to listen to + for HTTP connections. |
Printcap | /etc/printcap | Specifies the location of + a Berkeley printcap file to update with a list of current printers and + classes. If no filename is supplied then this automatic generation is + disabled. |
RequestRoot | /var/spool/cups | Specifies the + location of request files. |
RIPCache | 8m | Specifies the size of the memory + cache in bytes that is used by RIP filters. |
ServerAdmin | root@ServerName | Specifies the person + to contact with problems. |
ServerName | hostname | Specifies the hostname that + is supplied to HTTP clients. This is also used to determine the default + CUPS server for the CUPS IPP client applications. |
ServerRoot | /etc/cups | Specifies the root + directory for server configuration files. |
SystemGroup | root, sys, system | Specifies the + group name used for System class authentication. |
TempDir | /var/tmp | Specifies the temporary + directory to use. |
Timeout | 300 | The timeout in seconds before client + connections are closed in the middle of a request. |
User | lp | Specifies the user that is used when + running external programs. |
The printers.conf file consists of 1 or more lines of ASCII text. - Comment lines start with the pound ("#") character.
-Each non-blank line starts with the name of a configuration -directive followed by its value. The following directives are -understood: +
The printers.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.
+Each non-blank line starts with the name of a configuration directive + followed by its value. The following directives are understood:
Directive | Description |
---|---|
Accepting | Specifies whether the printer is accepting -new jobs. May be the names "Yes" or "No". |
Accepting | Specifies whether the printer is accepting new + jobs. May be the names "Yes" or "No". |
<DefaultPrinter name>
- </Printer> | Surrounds the printer definition for a default -destination. |
AllowUsers | Specifies a list of users that are allowed -to access the printer. |
BannerStart | Specifies the banner that is printed before -other files in a job. |
BannerEnd | Specifies the banner that is printed after -other files in a job. |
DenyUsers | Specifies a list of users that are not -allowed to access the printer. |
DeviceURI | Specifies the device-uri attribute for the -printer. | Surrounds the printer definition for a default + destination. | +
AllowUsers | Specifies a list of users that are allowed to + access the printer. |
BannerStart | Specifies the banner that is printed before + other files in a job. |
BannerEnd | Specifies the banner that is printed after + other files in a job. |
DenyUsers | Specifies a list of users that are not allowed + to access the printer. |
DeviceURI | Specifies the device-uri attribute for the + printer. |
Info | A textual description of the printer. |
Location | A textual location of the printer. |
<Printer name>
</Printer> | Surrounds the printer definition. |
State | Specifies the initial state of the printer; can -be "Idle" or "Stopped". |
StateMessage | Specifies a textual message for the -current printer state. |
State | Specifies the initial state of the printer; can be + "Idle" or "Stopped". |
StateMessage | Specifies a textual message for the current + printer state. |
The AppSocket protocol is an 8-bit clean TCP/IP socket connection. -The default IP service port is 9100. The URI method name is "socket".
-The AppSocket protocol is used by the Hewlett Packard JetDirect -network interfaces and print servers, as well as many other vendors' -products. See the CUPS Software Administrators Manual for a list of -supported products.
+The AppSocket protocol is an 8-bit clean TCP/IP socket connection. + The default IP service port is 9100. The URI method name is "socket".
+The AppSocket protocol is used by the Hewlett Packard JetDirect + network interfaces and print servers, as well as many other vendors' + products. See the CUPS Software Administrators Manual for a list of + supported products.
The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By -default this service operates on IP service port 631.
-Each broadcast packet describes the state of a single printer or -class and is an ASCII text string of up to 1450 bytes ending with a -newline (0x0a). The string is formatted as follows:
+The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By + default this service operates on IP service port 631.
+Each broadcast packet describes the state of a single printer or + class and is an ASCII text string of up to 1450 bytes ending with a + newline (0x0a). The string is formatted as follows:
type SP state SP uri SP "location" SP "info" SP "make-and-model" NL-
State, uri, location, info, and make-and-model
-, correspond to the IPP State, uri, location, info, and make-and-model,
+ correspond to the IPP Type is a hexadecimal number string representing
-capability/type bits:
+printer-infoprinter-state
,
+
, and printer-state
,
printer-uri-supported
, printer-location
,
-printer-info
, and printer-make-and-model
- attributes. printer-make-and-model
attributes.
Type is a hexadecimal number string representing + capability/type bits:
Bit | Description |
---|
@@ -840,27 +835,27 @@ a CUPS Form file:
4.4 CUPS PostScript File-CUPS PostScript files are device-dependent Adobe PostScript program -files. The PostScript language is described in the - Adobe PostScript Language Reference Manual, Third Edition. +CUPS PostScript files are device-dependent Adobe PostScript program + files. The PostScript language is described in the + Adobe PostScript Language Reference Manual, Third Edition. The MIME type for CUPS PostScript files is 4.5 CUPS Raster File-CUPS raster files are device-dependent raster image files that -contain a PostScript page device dictionary and device-dependent raster -imagery for each page in the document. These files are used to transfer -raster data from the PostScript and image file RIPs to device-dependent -filters that convert the raster data to a printable format. -A raster file begins with a four byte synchronization word: -0x52615374 ("RaSt") for big-endian architectures and 0x74536152 -("tSaR") for little-endian architectures. The writer of the raster -file will use the native word order, and the reader is responsible for -detecting a reversed word order file and swapping bytes as needed. The -CUPS Image Library raster functions perform this function -automatically. -Following the synchronization word are a series of raster pages. - Each page starts with a page device dictionary header and is followed -immediately by the raster data for that page. + CUPS raster files are device-dependent raster image files that + contain a PostScript page device dictionary and device-dependent raster + imagery for each page in the document. These files are used to transfer + raster data from the PostScript and image file RIPs to device-dependent + filters that convert the raster data to a printable format. +A raster file begins with a four byte synchronization word: + 0x52615374 ("RaSt") for big-endian architectures and 0x74536152 + ("tSaR") for little-endian architectures. The writer of the raster file + will use the native word order, and the reader is responsible for + detecting a reversed word order file and swapping bytes as needed. The + CUPS Image Library raster functions perform this function + automatically. +Following the synchronization word are a series of raster pages. Each + page starts with a page device dictionary header and is followed + immediately by the raster data for that page.
Description-
Example#include <cups/cups.h> @@ -4062,9 +4042,9 @@ cups_option_t *options; cupsFreeOptions(num_options, options); See Also-cupsAddOption(), -cupsGetOption(), cupsMarkOptions(), cupsParseOptions() + cupsAddOption(), + cupsGetOption(), cupsMarkOptions(), cupsParseOptions() cupsGetClasses()@@ -4081,11 +4061,11 @@ cupsGetClasses(char ***classes); |
The number of printer classes available.
+The number of printer classes available.
cupsGetClasses()
gets a list of the available printer
-classes. The returned array should be freed using the free()
- when it is no longer needed.
cupsGetClasses()
gets a list of the available printer
+ classes. The returned array should be freed using the free()
+ when it is no longer needed.
#include <cups/cups.h> @@ -4102,15 +4082,15 @@ num_classes = cupsGetClasses( if (num_classes > 0) { - for (i = 0; i num_classes; i ++) + for (i = 0; i <num_classes; i ++) free(classes[i]); free(classes); }
cupsGetDefault(), -cupsGetPrinters() +
A pointer to the default destination.
+A pointer to the default destination.
cupsGetDefault()
gets the default destination printer
-or class. The default destination is stored in a static string and will
-be overwritten (usually with the same value) after each call.
cupsGetDefault()
gets the default destination printer or
+ class. The default destination is stored in a static string and will be
+ overwritten (usually with the same value) after each call.
#include <cups/cups.h> @@ -4132,8 +4112,8 @@ be overwritten (usually with the same value) after each call. printf("The default destination is %s\n", cupsGetDefault());
cupsGetClasses(), -cupsGetPrinters() +
A pointer to the option values or NULL
if the option is
-not defined.
A pointer to the option values or NULL
if the option is
+ not defined.
cupsGetOption()
returns the first occurrence of the
-named option. If the option is not included in the options array then a
-NULL
pointer is returned.
cupsGetOption()
returns the first occurrence of the
+ named option. If the option is not included in the options array then a
+ NULL
pointer is returned.
#include <cups/cups.h> @@ -4172,9 +4152,9 @@ const char *media; media = cupsGetOption("media", num_options, options);
cupsAddOption(), -cupsFreeOptions(), cupsMarkOptions() -, cupsParseOptions() +
cupsAddOption(), + cupsFreeOptions(), cupsMarkOptions() +, cupsParseOptions()
A pointer to the password that was entered or NULL
if
-no password was entered.
A pointer to the password that was entered or NULL
if no
+ password was entered.
cupsGetPassword()
displays the prompt string and asks
-the user for a password. The password text is not echoed to the user.
cupsGetPassword()
displays the prompt string and asks
+ the user for a password. The password text is not echoed to the user.
#include <cups/cups.h> @@ -4207,9 +4187,9 @@ char *password; password = cupsGetPassword("Please enter a password:");
cupsServer(), -cupsSetPasswordCB(), cupsSetServer(), cupsSetUser(), cupsUser() +
cupsServer(), + cupsSetPasswordCB(), cupsSetServer(), cupsSetUser(), cupsUser()
@@ -4228,14 +4208,14 @@ cupsGetPPD(const char *printer);The name of a temporary file containing the PPD file or NULL
- if the printer cannot be located or does not have a PPD file.
cupsGetPPD()
gets a copy of the PPD file for the named
-printer. The printer name can be of the form "printer" or
-"printer@hostname".
You should remove (unlink) the PPD file after you are done using it.
-The filename is stored in a static buffer and will be overwritten with
-each call to cupsGetPPD()
.
cupsGetPPD()
gets a copy of the PPD file for the named
+ printer. The printer name can be of the form "printer" or
+ "printer@hostname".
You should remove (unlink) the PPD file after you are done using it.
+ The filename is stored in a static buffer and will be overwritten with
+ each call to cupsGetPPD()
.
#include <cups/cups.h> @@ -4252,7 +4232,6 @@ unlink(ppd);-
@@ -4267,11 +4246,11 @@ cupsGetPrinters(char ***printers);Returns
-The number of printer printers available.
+The number of printer printers available.
Description
-+
cupsGetPrinters()
gets a list of the available -printers. The returned array should be freed using thefree()
- when it is no longer needed.
cupsGetPrinters()
gets a list of the available printers. + The returned array should be freed using thefree()
when + it is no longer needed.Example
#include <cups/cups.h> @@ -4288,15 +4267,15 @@ num_printers = cupsGetPrinters( if (num_printers > 0) { - for (i = 0; i num_printers; i ++) + for (i = 0; i <num_printers; i ++) free(printers[i]); free(printers); }See Also
-cupsGetClasses(), -cupsGetDefault() +
cupsLangDefault()
@@ -4306,14 +4285,14 @@ const char * cupsLangDefault(void);
A pointer to the default language structure.
+A pointer to the default language structure.
cupsLangDefault()
returns a language structure for the
-default language. The default language is defined by the LANG
- environment variable. If the specified language cannot be located then
-the POSIX (English) locale is used.
Call cupsLangFree()
to free any memory associated with
-the language structure when you are done.
cupsLangDefault()
returns a language structure for the
+ default language. The default language is defined by the LANG
+ environment variable. If the specified language cannot be located then
+ the POSIX (English) locale is used.
Call cupsLangFree()
to free any memory associated with
+ the language structure when you are done.
#include <cups/language.h> @@ -4328,9 +4307,9 @@ language = cupsLangDefault(); cupsLangFree(language);
cupsLangEncoding(), -cupsLangFlush(), cupsLangFree(), -cupsLangGet(), cupsLangString() +
cupsLangEncoding(), + cupsLangFlush(), cupsLangFree(), + cupsLangGet(), cupsLangString()
A pointer to the encoding string.
+A pointer to the encoding string.
cupsLangEncoding()
returns the language encoding used
-for the specified language, e.g. "iso-8859-1", "utf-8", etc.
cupsLangEncoding()
returns the language encoding used
+ for the specified language, e.g. "iso-8859-1", "utf-8", etc.
#include <cups/language.h> @@ -4366,9 +4345,9 @@ encoding = cupsLangEncoding(language); cupsLangFree(language);
cupsLangDefault(), -cupsLangFlush(), cupsLangFree(), -cupsLangGet(), cupsLangString() +
cupsLangDefault(), + cupsLangFlush(), cupsLangFree(), + cupsLangGet(), cupsLangString()
cupsLangFlush()
frees all language structures that have
-been allocated.
cupsLangFlush()
frees all language structures that have
+ been allocated.
#include <cups/language.h> @@ -4389,9 +4368,9 @@ been allocated. cupsLangFlush();
cupsLangDefault(), -cupsLangEncoding(), cupsLangFree(), -cupsLangGet(), cupsLangString() +
cupsLangDefault(), + cupsLangEncoding(), cupsLangFree(), + cupsLangGet(), cupsLangString()
cupsLangFree()
frees the specified language structure.
cupsLangFree()
frees the specified language structure.
#include <cups/language.h> @@ -4419,9 +4398,9 @@ cups_lang_t *language; cupsLangFree(language);
cupsLangDefault(), -cupsLangEncoding(), cupsLangFlush(), -cupsLangGet(), cupsLangString() +
cupsLangDefault(), + cupsLangEncoding(), cupsLangFlush(), + cupsLangGet(), cupsLangString()
A pointer to a language structure.
+A pointer to a language structure.
cupsLangGet()
returns a language structure for the
-specified locale. If the locale is not defined then the POSIX (English)
-locale is substituted.
cupsLangGet()
returns a language structure for the
+ specified locale. If the locale is not defined then the POSIX (English)
+ locale is substituted.
#include <cups/language.h> @@ -4458,9 +4437,9 @@ language = cupsLangGet("fr"); cupsLangFree(language);
cupsLangDefault(), -cupsLangEncoding(), cupsLangFlush(), -cupsLangFree(), cupsLangString() +
cupsLangDefault(), + cupsLangEncoding(), cupsLangFlush(), + cupsLangFree(), cupsLangString()
A pointer to the message string or NULL
if the message
-is not defined.
A pointer to the message string or NULL
if the message
+ is not defined.
cupsLangString()
returns a pointer to the specified
-message string in the specified language.
cupsLangString()
returns a pointer to the specified
+ message string in the specified language.
#include <cups/language.h> @@ -4501,9 +4480,9 @@ s = cupsLangString(language, CUPS_MSG_YES); cupsLangFree(language);
cupsLangDefault(), -cupsLangEncoding(), cupsLangFlush(), -cupsLangFree(), cupsLangGet() +
cupsLangDefault(), + cupsLangEncoding(), cupsLangFlush(), + cupsLangFree(), cupsLangGet()
An enumeration containing the last IPP error.
+An enumeration containing the last IPP error.
cupsLastError()
returns the last IPP error that
-occurred. If no error occurred then it will return IPP_OK
- or IPP_OK_CONFLICT
.
cupsLastError()
returns the last IPP error that
+ occurred. If no error occurred then it will return IPP_OK
+ or IPP_OK_CONFLICT
.
#include <cups/cups.h> @@ -4529,8 +4508,8 @@ ipp_status_t status; status = cupsLastError();
cupsCancelJob(), -cupsPrintFile() +
cupsCancelJob(), + cupsPrintFile()
The number of conflicts found.
+The number of conflicts found.
cupsMarkOptions()
marks options in the PPD file. It
-also handles mapping of IPP option names and values to PPD option
-names.
cupsMarkOptions()
marks options in the PPD file. It also
+ handles mapping of IPP option names and values to PPD option names.
#include <cups/cups.h> @@ -4570,9 +4548,9 @@ ppd_file_t *ppd; cupsMarkOptions(ppd, num_options, options);
cupsAddOption(), -cupsFreeOptions(), cupsGetOption(), -cupsParseOptions() +
cupsAddOption(), + cupsFreeOptions(), cupsGetOption(), + cupsParseOptions()
The new number of options in the array.
+The new number of options in the array.
cupsParseOptions()
parses the specifies string for one
-or more options of the form "name=value", "name", or "noname". It can
-be called multiple times to combine the options from several strings.
cupsParseOptions()
parses the specifies string for one
+ or more options of the form "name=value", "name", or "noname". It can
+ be called multiple times to combine the options from several strings.
#include <cups/cups.h> @@ -4613,9 +4591,9 @@ options = (cups_option_t *)0; num_options = cupsParseOptions(argv[5], num_options, &options);
cupsAddOption(), -cupsFreeOptions(), cupsGetOption(), -cupsMarkOptions() +
cupsAddOption(), + cupsFreeOptions(), cupsGetOption(), + cupsMarkOptions()
The new job ID number or 0 on error.
+The new job ID number or 0 on error.
cupsPrintFile()
sends a file to the specified printer
-or class for printing. If the job cannot be printed the error code can
-be found by calling cupsLastError()
.
cupsPrintFile()
sends a file to the specified printer or
+ class for printing. If the job cannot be printed the error code can be
+ found by calling cupsLastError()
.
#include <cups/cups.h> @@ -4660,10 +4638,9 @@ jobid = cupsPrintFile("printer@hostname", "filename.ps", &qu num_options, options);
cupsCancelJob(), -cupsLastError(), cupsPrintFiles() +
cupsCancelJob(), + cupsLastError(), cupsPrintFiles() -
The new job ID number or 0 on error.
+The new job ID number or 0 on error.
cupsPrintFiles()
sends multiple files to the specified
-printer or class for printing. If the job cannot be printed the error
-code can be found by calling cupsLastError()
.
cupsPrintFiles()
sends multiple files to the specified
+ printer or class for printing. If the job cannot be printed the error
+ code can be found by calling cupsLastError()
.
#include <cups/cups.h> @@ -4711,8 +4688,8 @@ jobid = cupsPrintFiles("printer@hostname", num_files, files, "Job Title", num_options, options);
cupsCancelJob(), -cupsLastError(), cupsPrintFile() +
cupsCancelJob(), + cupsLastError(), cupsPrintFile()
cupsRasterClose()
closes the specified raster stream.
cupsRasterClose()
closes the specified raster stream.
#include <cups/raster.h> @@ -4741,11 +4718,11 @@ cups_raster_t *ras; cupsRasterClose(ras);
cupsRasterOpen(), -cupsRasterReadHeader(), -cupsRasterReadPixels(), -cupsRasterWriteHeader(), -cupsRasterWritePixels() +
cupsRasterOpen(), + cupsRasterReadHeader(), + cupsRasterReadPixels(), + cupsRasterWriteHeader(), + cupsRasterWritePixels()
CUPS_RASTER_READ
or
- CUPS_RASTER_WRITE
.A pointer to a raster stream or NULL
if there was an
-error.
A pointer to a raster stream or NULL
if there was an
+ error.
cupsRasterOpen()
opens a raster stream for reading or
-writing.
cupsRasterOpen()
opens a raster stream for reading or
+ writing.
#include <cups/raster.h> @@ -4781,11 +4758,11 @@ cups_raster_t *ras; ras = cupsRasterOpen(0, CUPS_RASTER_READ);
cupsRasterClose(), -cupsRasterReadHeader(), -cupsRasterReadPixels(), -cupsRasterWriteHeader(), -cupsRasterWritePixels() +
cupsRasterClose(), + cupsRasterReadHeader(), + cupsRasterReadPixels(), + cupsRasterWriteHeader(), + cupsRasterWritePixels()
Argument | Description |
---|---|
ras | The raster stream to read from. |
header | A pointer to a page header structure to read -into. |
header | A pointer to a page header structure to read + into. |
1 on success, 0 on EOF or error.
+1 on success, 0 on EOF or error.
cupsRasterReadHeader()
reads a page header from the
-specified raster stream.
cupsRasterReadHeader()
reads a page header from the
+ specified raster stream.
#include <cups/raster.h> @@ -4832,11 +4809,11 @@ while (cupsRasterReadHeader(ras, &header)) }
cupsRasterClose(), -cupsRasterOpen(), -cupsRasterReadPixels(), -cupsRasterWriteHeader(), -cupsRasterWritePixels() +
cupsRasterClose(), + cupsRasterOpen(), + cupsRasterReadPixels(), + cupsRasterWriteHeader(), + cupsRasterWritePixels()
The number of bytes read or 0 on EOF or error.
+The number of bytes read or 0 on EOF or error.
cupsRasterReadPixels()
reads pixel data from the
-specified raster stream.
cupsRasterReadPixels()
reads pixel data from the
+ specified raster stream.
#include <cups/raster.h> @@ -4884,11 +4861,11 @@ while (cupsRasterReadHeader(ras, &header)) }
cupsRasterClose(), -cupsRasterOpen(), -cupsRasterReadHeader(), -cupsRasterWriteHeader(), -cupsRasterWritePixels() +
cupsRasterClose(), + cupsRasterOpen(), + cupsRasterReadHeader(), + cupsRasterWriteHeader(), + cupsRasterWritePixels()
1 on success, 0 on error.
+1 on success, 0 on error.
cupsRasterWriteHeader()
writes the specified page
-header to a raster stream.
cupsRasterWriteHeader()
writes the specified page header
+ to a raster stream.
#include <cups/raster.h> @@ -4931,11 +4908,11 @@ for (line = 0; line < header.cupsHeight; line ++) }
cupsRasterClose(), -cupsRasterOpen(), -cupsRasterReadHeader(), -cupsRasterReadPixels(), -cupsRasterWritePixels() +
cupsRasterClose(), + cupsRasterOpen(), + cupsRasterReadHeader(), + cupsRasterReadPixels(), + cupsRasterWritePixels()
The number of bytes written.
+The number of bytes written.
cupsRasterWritePixels()
writes the specified pixel data
-to a raster stream.
cupsRasterWritePixels()
writes the specified pixel data
+ to a raster stream.
#include <cups/raster.h> @@ -4980,11 +4957,11 @@ for (line = 0; line < header.cupsHeight; line ++) }
cupsRasterClose(), -cupsRasterOpen(), -cupsRasterReadHeader(), -cupsRasterReadPixels(), -cupsRasterWriteHeader() +
cupsRasterClose(), + cupsRasterOpen(), + cupsRasterReadHeader(), + cupsRasterReadPixels(), + cupsRasterWriteHeader()
A pointer to the default server name.
+A pointer to the default server name.
cupsServer()
returns a pointer to the default server
-name. The server name is stored in a static location and will be
-overwritten with every call to cupsServer()
The default server is determined from the following locations:
+cupsServer()
returns a pointer to the default server
+ name. The server name is stored in a static location and will be
+ overwritten with every call to cupsServer()
The default server is determined from the following locations:
CUPS_SERVER
environment variable, ServerName
directive in the client.conf
- file, CUPS_SERVER
environment variable,ServerName
directive in the client.conf
+ file,@@ -5015,9 +4992,9 @@ const char *server; server = cupsServer();
cupsGetPassword(), -cupsSetPasswordCB(), cupsSetServer(), cupsSetUser(), cupsUser() +
cupsGetPassword(), + cupsSetPasswordCB(), cupsSetServer(), cupsSetUser(), cupsUser()
@@ -5035,11 +5012,11 @@ cupsSetPasswordCB(const char *(*cb)(const char *prompt));cupsSetPasswordCB()
sets the callback function to use
-when asking the user for a password. The callback function must accept
-a single character string pointer (the prompt string) and return
-NULL
if the user did not enter a password string or a pointer to
-the password string otherwise.
cupsSetPasswordCB()
sets the callback function to use
+ when asking the user for a password. The callback function must accept
+ a single character string pointer (the prompt string) and return
+NULL
if the user did not enter a password string or a pointer to
+ the password string otherwise.
#include <cups/cups.h> @@ -5060,9 +5037,9 @@ cupsSetPasswordCB(my_password_cb); password = cupsGetPassword("Please enter a password:");
cupsServer(), -cupsSetServer(), cupsSetUser(), -cupsUser() +
cupsServer(), + cupsSetServer(), cupsSetUser(), + cupsUser()
cupsSetServer()
sets the default server to use for the
-CUPS API. If the server
argument is NULL
, the
-default server is used.
cupsSetServer()
sets the default server to use for the
+ CUPS API. If the server
argument is NULL
, the
+ default server is used.
#include <cups/cups.h> @@ -5089,9 +5066,9 @@ default server is used. cupsSetServer("foo.bar.com");
cupsServer(), -cupsSetPasswordCB(), cupsSetUser(), -cupsUser() +
cupsServer(), + cupsSetPasswordCB(), cupsSetUser(), + cupsUser()
cupsSetUser()
sets the default user name for
-authentication. If the user
argument is NULL
- then the current login user is used.
cupsSetUser()
sets the default user name for
+ authentication. If the user
argument is NULL
+ then the current login user is used.
#include <cups/cups.h> @@ -5120,9 +5097,9 @@ authentication. If theuser
argument isNULL
cupsSetUser("root");
cupsServer(), -cupsSetPasswordCB(), cupsSetServer(), cupsUser() +
cupsServer(), + cupsSetPasswordCB(), cupsSetServer(), cupsUser()
Argument | Description |
---|---|
filename | The character string to hold the temporary -filename. |
filename | The character string to hold the temporary + filename. |
length | The size of the filename string in bytes. |
A pointer to filename
.
A pointer to filename
.
cupsTempFile()
generates a temporary filename for the
-/var/tmp directory or the directory specified by the TMPDIR
- environment variable.
cupsTempFile()
generates a temporary filename for the
+ /var/tmp directory or the directory specified by the TMPDIR
+ environment variable.
#include <cups/cups.h> @@ -5157,7 +5134,6 @@ cupsTempFile(filename, sizeof(filename));-
@@ -5165,11 +5141,11 @@ const char * cupsUser(void);
A pointer to the current username or NULL
if the user
-ID is undefined.
A pointer to the current username or NULL
if the user ID
+ is undefined.
cupsUser()
returns the name associated with the current
-user ID as reported by the getuid()
system call.
cupsUser()
returns the name associated with the current
+ user ID as reported by the getuid()
system call.
#include <cups/cups.h> @@ -5179,8 +5155,8 @@ const char *user; user = cupsUser();
cupsGetPassword(), -cupsServer() +
cupsGetPassword(), + cupsServer()
Argument | Description |
---|---|
http | The HTTP connection |
blocking | 0 if the connection should be non-blocking, 1 -if it should be blocking |
blocking | 0 if the connection should be non-blocking, 1 + if it should be blocking |
The httpBlocking()
function sets the blocking mode for
-the HTTP connection. By default HTTP connections will block (stop) the
-client program until data is available or can be sent to the server.
The httpBlocking()
function sets the blocking mode for
+ the HTTP connection. By default HTTP connections will block (stop) the
+ client program until data is available or can be sent to the server.
#include <cups/http.h> @@ -5211,8 +5187,8 @@ http = httpConnect("server", port); httpBlocking(http, 0);
httpCheck()
,
-httpConnect()
+ httpCheck()
,
+ httpConnect()
0 if there is no data pending, 1 otherwise.
+0 if there is no data pending, 1 otherwise.
The httpCheck()
function checks to see if there is any
-data pending on an HTTP connection.
The httpCheck()
function checks to see if there is any
+ data pending on an HTTP connection.
#include <cups/http.h> @@ -5244,9 +5220,9 @@ if (httpCheck(http)) }
httpBlocking()
,
-httpConnect()
, httpGets()
-, httpRead()
+ httpBlocking()
,
+ httpConnect()
, httpGets()
+, httpRead()
The httpClearFields()
function clears all HTTP request
-fields for the HTTP connection.
The httpClearFields()
function clears all HTTP request
+ fields for the HTTP connection.
#include <cups/http.h> @@ -5273,8 +5249,8 @@ http_t *http; httpClearFields(http);
httpConnect()
,
-httpGetField()
,
+ httpConnect()
,
+ httpGetField()
,
httpSetField()
@@ -5291,8 +5267,8 @@ void httpClose(http_t *http);
Description
-The httpClose()
function closes an active HTTP
-connection.
+The httpClose()
function closes an active HTTP
+ connection.
Example
#include <cups/http.h>
@@ -5302,7 +5278,7 @@ http_t *http;
httpClose(http);
See Also
- httpConnect()
+ httpConnect()
httpConnect()
@@ -5314,17 +5290,17 @@ http_t *httpConnect(const char *hostname, int port);
Argument Description
-hostname The name or IP address of the server to
-connect to
+hostname The name or IP address of the server to connect
+ to
port The port number to use
Returns
-A pointer to a HTTP connection structure or NULL if the connection
-could not be made.
+A pointer to a HTTP connection structure or NULL if the connection
+ could not be made.
Description
-The httpConnect()
function opens a HTTP connection to
-the specified server and port.
+The httpConnect()
function opens a HTTP connection to
+ the specified server and port.
Example
#include <cups/http.h>
@@ -5334,10 +5310,10 @@ http_t *http;
http = httpConnect(cupsServer(), ippPort());
See Also
- httpClose()
,
-httpGet()
, httpGets()
, httpPost()
,
-httpRead()
, httpWrite()
+ httpClose()
,
+httpGet()
, httpGets()
,
+ httpPost()
, httpRead()
+, httpWrite()
httpDecode64()
@@ -5354,10 +5330,10 @@ char *httpDecode64(char *out, const char *in);
Returns
-A pointer to the decoded string.
+A pointer to the decoded string.
Description
-The httpDecode64()
function decodes a base-64 encoded
-string to the original string.
+The httpDecode64()
function decodes a base-64 encoded
+ string to the original string.
Example
#include <cups/http.h>
@@ -5368,7 +5344,7 @@ char original_string[255];
httpDecode64(original_string, encoded_string);
See Also
- httpEncode64()
+ httpEncode64()
httpDelete()
@@ -5385,10 +5361,10 @@ int httpDelete(http_t *http, const char *uri);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpDelete()
function sends a HTTP DELETE request
-to the server.
+The httpDelete()
function sends a HTTP DELETE request to
+ the server.
Example
#include <cups/http.h>
@@ -5398,8 +5374,8 @@ http_t *http;
httpDelete(http, "/some/uri");
See Also
- httpConnect()
,
-httpSetField()
,
+ httpConnect()
,
+ httpSetField()
,
httpUpdate()
@@ -5417,10 +5393,10 @@ char *httpEncode64(char *out, const char *in);
Returns
-A pointer to the encoded string.
+A pointer to the encoded string.
Description
-The httpEncode64()
function decodes a base-64 encoded
-string to the original string.
+The httpEncode64()
function decodes a base-64 encoded
+ string to the original string.
Example
#include <cups/http.h>
@@ -5431,7 +5407,7 @@ char original_string[255];
httpEncode64(encoded_string, original_string);
See Also
- httpDecode64()
+ httpDecode64()
httpError()
@@ -5447,10 +5423,10 @@ int httpError(http_t *http);
Returns
-The last error that occurred or 0 if no error has occurred.
+The last error that occurred or 0 if no error has occurred.
Description
-The httpError()
function returns the last error that
-occurred on the HTTP connection.
+The httpError()
function returns the last error that
+ occurred on the HTTP connection.
Example
#include <cups/http.h>
@@ -5463,7 +5439,7 @@ if (httpError(http))
}
See Also
- httpConnect()
+ httpConnect()
httpFlush()
@@ -5479,8 +5455,8 @@ void httpFlush(http_t *http);
Description
-The httpFlush()
function flushes any remaining data
-left from a GET or POST operation.
+The httpFlush()
function flushes any remaining data left
+ from a GET or POST operation.
Example
#include <cups/http.h>
@@ -5490,7 +5466,7 @@ http_t *http;
httpFlush(http);
See Also
- httpConnect()
,
+ httpConnect()
,
httpGet()
@@ -5507,10 +5483,10 @@ int httpGet(http_t *http, const char *uri);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpGet()
function sends a HTTP GET request to the
-server.
+The httpGet()
function sends a HTTP GET request to the
+ server.
Example
#include <cups/http.h>
@@ -5520,8 +5496,8 @@ http_t *http;
httpGet(http, "/some/uri");
See Also
- httpConnect()
,
-httpSetField()
,
+ httpConnect()
,
+ httpSetField()
,
httpUpdate()
@@ -5534,17 +5510,17 @@ char *httpGets(char *line, int length, http_t *http)
Argument Description
-line The string to fill with a line from the HTTP
-connection
+line The string to fill with a line from the HTTP
+ connection
length The maximum length of the string
http The HTTP connection
Returns
-A pointer to the string or NULL if no line could be retrieved.
+A pointer to the string or NULL if no line could be retrieved.
Description
-The httpGets()
function is used to read a request line
-from the HTTP connection. It is not normally used by a client program.
+The httpGets()
function is used to read a request line
+ from the HTTP connection. It is not normally used by a client program.
Example
#include <cups/http.h>
@@ -5558,8 +5534,8 @@ if (httpGets(line, sizeof(line), http))
}
See Also
- httpConnect()
,
-httpUpdate()
+ httpConnect()
,
+ httpUpdate()
httpGetDateString()
@@ -5575,11 +5551,11 @@ const char *httpGetDateString(time_t time)
Returns
-A pointer to a static string containing the HTTP date/time string
-for the specified UNIX time value.
+A pointer to a static string containing the HTTP date/time string for
+ the specified UNIX time value.
Description
-The httpGetDateString()
function generates a date/time
-string suitable for HTTP requests from a UNIX time value.
+The httpGetDateString()
function generates a date/time
+ string suitable for HTTP requests from a UNIX time value.
Example
#include <cups/http.h>
@@ -5587,7 +5563,7 @@ string suitable for HTTP requests from a UNIX time value.
puts(httpGetDateString(time(NULL)));
See Also
- httpGetDateTime()
+ httpGetDateTime()
httpGetDateTime()
@@ -5603,10 +5579,10 @@ time_t httpGetDateTime(const char *date)
Returns
-A UNIX time value.
+A UNIX time value.
Description
-The httpGetDateTime()
function converts a HTTP
-date/time string to a UNIX time value.
+The httpGetDateTime()
function converts a HTTP date/time
+ string to a UNIX time value.
Example
#include <cups/http.h>
@@ -5614,7 +5590,7 @@ date/time string to a UNIX time value.
printf("%d\n", httpGetDateTime("Fri, 30 June 2000 12:34:56 GMT"));
See Also
- httpGetDateString()
+ httpGetDateString()
httpGetField()
@@ -5631,10 +5607,10 @@ const char *httpGetField(http_t *http, http_field_t field);
Returns
-A pointer to the field value string.
+A pointer to the field value string.
Description
-The httpGetField()
function returns the current value
-for the specified HTTP field.
+The httpGetField()
function returns the current value
+ for the specified HTTP field.
Example
#include <cups/http.h>
@@ -5647,8 +5623,8 @@ while (httpUpdate(http) == HTTP_CONTINUE);
puts(httpGetField(http, HTTP_FIELD_CONTENT_TYPE));
See Also
- httpConnect()
,
-httpSetField()
+ httpConnect()
,
+ httpSetField()
httpHead()
@@ -5665,10 +5641,10 @@ int httpHead(http_t *http, const char *uri);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpHead()
function sends a HTTP HEAD request to
-the server.
+The httpHead()
function sends a HTTP HEAD request to the
+ server.
Example
#include <cups/http.h>
@@ -5678,8 +5654,8 @@ http_t *http;
httpHead(http, "/some/uri");
See Also
- httpConnect()
,
-httpSetField()
,
+ httpConnect()
,
+ httpSetField()
,
httpUpdate()
@@ -5689,9 +5665,9 @@ httpUpdate()
void httpInitialize(void);
Description
-The httpInitialize()
function initializes the
-networking code as needed by the underlying platform. It is called
-automatically by the httpConnect()
function.
+The httpInitialize()
function initializes the networking
+ code as needed by the underlying platform. It is called automatically
+ by the httpConnect()
function.
Example
#include <cups/http.h>
@@ -5699,7 +5675,7 @@ automatically by the httpConnect()
function.
httpInitialize();
See Also
- httpConnect()
+ httpConnect()
httpOptions()
@@ -5716,10 +5692,10 @@ int httpOptions(http_t *http, const char *uri);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpOptions()
function sends a HTTP OPTIONS request
-to the server.
+The httpOptions()
function sends a HTTP OPTIONS request
+ to the server.
Example
#include <cups/http.h>
@@ -5729,8 +5705,8 @@ http_t *http;
httpOptions(http, "/some/uri");
See Also
- httpConnect()
,
-httpSetField()
,
+ httpConnect()
,
+ httpSetField()
,
httpUpdate()
@@ -5748,10 +5724,10 @@ int httpPost(http_t *http, const char *uri);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpPost()
function sends a HTTP POST request to
-the server.
+The httpPost()
function sends a HTTP POST request to the
+ server.
Example
#include <cups/http.h>
@@ -5761,8 +5737,8 @@ http_t *http;
httpPost(http, "/some/uri");
See Also
- httpConnect()
,
-httpSetField()
,
+ httpConnect()
,
+ httpSetField()
,
httpUpdate()
@@ -5780,11 +5756,11 @@ int httpPrintf(http_t *http, const char *format, ...);
Returns
-The number of bytes written.
+The number of bytes written.
Description
-The httpPrintf()
function sends a formatted string to
-the HTTP connection. It is normally only used by the CUPS API and
-scheduler.
+The httpPrintf()
function sends a formatted string to
+ the HTTP connection. It is normally only used by the CUPS API and
+ scheduler.
Example
#include <cups/http.h>
@@ -5794,7 +5770,7 @@ http_t *http;
httpPrintf(http, "GET / HTTP/1.1 \r\n");
See Also
- httpConnect()
+ httpConnect()
httpPut()
@@ -5811,10 +5787,10 @@ int httpPut(http_t *http, const char *uri);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpPut()
function sends a HTTP PUT request to the
-server.
+The httpPut()
function sends a HTTP PUT request to the
+ server.
Example
#include <cups/http.h>
@@ -5824,8 +5800,8 @@ http_t *http;
httpDelete(http, "/some/uri");
See Also
- httpConnect()
,
-httpSetField()
,
+ httpConnect()
,
+ httpSetField()
,
httpUpdate()
@@ -5844,10 +5820,10 @@ int httpRead(http_t *http, char *buffer, int length);
Returns
-The number of bytes read or -1 on error.
+The number of bytes read or -1 on error.
Description
-The httpRead()
function reads data from the HTTP
-connection, possibly the result of a GET or POST request.
+The httpRead()
function reads data from the HTTP
+ connection, possibly the result of a GET or POST request.
Example
#include <cups/http.h>
@@ -5865,8 +5841,8 @@ while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
}
See Also
- httpConnect()
,
-httpWrite()
+ httpConnect()
,
+ httpWrite()
httpReconnect()
@@ -5882,11 +5858,11 @@ int httpReconnect(http_t *http);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpReconnect()
function reconnects to the HTTP
-server. This is usually done automatically if the HTTP functions detect
-that the server connection has terminated.
+The httpReconnect()
function reconnects to the HTTP
+ server. This is usually done automatically if the HTTP functions detect
+ that the server connection has terminated.
Example
#include <cups/http.h>
@@ -5896,7 +5872,7 @@ http_t *http;
httpReconnect(http);
See Also
- httpConnect()
+ httpConnect()
httpSeparate()
@@ -5912,20 +5888,20 @@ void httpSeparate(const char *uri, char *method,
Argument Description
uri The URI to separate
method The method (scheme) of the URI
-username The username (and password) portion of the
-URI, if any
+username The username (and password) portion of the URI,
+ if any
host The hostname portion of the URI, if any
-port The port number for the URI, either as specified
-or as default for the method/scheme
-resource The resource string, usually a filename on the
-server
+port The port number for the URI, either as specified or
+ as default for the method/scheme
+resource The resource string, usually a filename on the
+ server
Description
-The httpSeparate()
function separates the specified URI
-into its component parts. The method, username, hostname, and resource
-strings should be at least HTTP_MAX_URI
characters long to
-avoid potential buffer overflow problems.
+The httpSeparate()
function separates the specified URI
+ into its component parts. The method, username, hostname, and resource
+ strings should be at least HTTP_MAX_URI
characters long to
+ avoid potential buffer overflow problems.
Example
char uri[HTTP_MAX_URI];
@@ -5938,7 +5914,7 @@ int port;
httpSeparate(uri, method, username, host, &port, resource);
See Also
- httpConnect()
+ httpConnect()
httpSetField()
@@ -5956,8 +5932,8 @@ void httpSetField(http_t *http, http_field_t field, const char *value);
Description
-The httpSetField()
function sets the current value for
-the specified HTTP field.
+The httpSetField()
function sets the current value for
+ the specified HTTP field.
Example
#include <cups/http.h>
@@ -5969,8 +5945,8 @@ httpGet(http, "/some/uri");
while (httpUpdate(http) == HTTP_CONTINUE);
See Also
- httpConnect()
,
-httpGetField()
+ httpConnect()
,
+ httpGetField()
httpTrace()
@@ -5987,10 +5963,10 @@ int httpTrace(http_t *http, const char *uri);
Returns
-0 on success, non-zero on failure.
+0 on success, non-zero on failure.
Description
-The httpTrace()
function sends a HTTP TRACE request to
-the server.
+The httpTrace()
function sends a HTTP TRACE request to
+ the server.
Example
#include <cups/http.h>
@@ -6000,8 +5976,8 @@ http_t *http;
httpTrace(http, "/some/uri");
See Also
- httpConnect()
,
-httpSetField()
,
+ httpConnect()
,
+ httpSetField()
,
httpUpdate()
@@ -6018,16 +5994,16 @@ http_status_t httpUpdate(http_t *http);
Returns
-The HTTP status of the current request.
+The HTTP status of the current request.
Description
-The httpUpdate()
function updates the current request
-status. It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or
-TRACE request to finalize the HTTP request and retrieve the request
-status.
-Since proxies and the current blocking mode can cause the request to
-take longer, programs should continue calling httpUpdate()
+
The httpUpdate()
function updates the current request
+ status. It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or
+ TRACE request to finalize the HTTP request and retrieve the request
+ status.
+Since proxies and the current blocking mode can cause the request to
+ take longer, programs should continue calling httpUpdate()
until the return status is not the constant value HTTP_CONTINUE
-.
+.
Example
#include <cups/http.h>
@@ -6040,12 +6016,12 @@ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
printf("Request status is %d\n", status);
See Also
- httpConnect()
,
-httpDelete()
, httpGet()
-, httpHead()
,
-httpOptions()
, httpPost()
-, httpPut()
,
-httpTrace()
+ httpConnect()
,
+ httpDelete()
, httpGet()
+, httpHead()
,
+ httpOptions()
, httpPost()
+, httpPut()
,
+ httpTrace()
httpWrite()
@@ -6063,10 +6039,10 @@ int httpWrite(http_t *http, char *buffer, int length);
Returns
-The number of bytes read or -1 on error.
+The number of bytes read or -1 on error.
Description
-The httpWrite()
function reads data from the HTTP
-connection, possibly the result of a GET or POST request.
+The httpWrite()
function reads data from the HTTP
+ connection, possibly the result of a GET or POST request.
Example
#include <cups/http.h>
@@ -6090,8 +6066,8 @@ while ((bytes = httpRead(http, buffer, sizeof(buffer) - 1)) > 0)
}
See Also
- httpConnect()
,
-httpRead()
+ httpConnect()
,
+ httpRead()
ippAddBoolean()
@@ -6111,11 +6087,11 @@ ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddBoolean()
function adds a single boolean
-attribute value to the specified IPP request.
+The ippAddBoolean()
function adds a single boolean
+ attribute value to the specified IPP request.
Example
#include <cups/ipp.h>
@@ -6125,15 +6101,15 @@ ipp_t *ipp;
ippAddBoolean(ipp, IPP_TAG_OPERATION, "my-jobs", 1);
See Also
- ippAddBooleans()
,
-ippAddDate()
,
-ippAddInteger()
,
-ippAddIntegers()
, ippAddRange()
-, ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBooleans()
,
+ ippAddDate()
,
+ippAddInteger()
,
+ippAddIntegers()
, ippAddRange()
+, ippAddRanges()
,
+ ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6156,13 +6132,13 @@ ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddBooleans()
function adds one or more boolean
-attribute values to the specified IPP request. If the values
+
The ippAddBooleans()
function adds one or more boolean
+ attribute values to the specified IPP request. If the values
pointer is NULL
then an array of num_values
- false values is created.
+ false values is created.
Example
#include <cups/ipp.h>
@@ -6173,15 +6149,15 @@ char values[10];
ippAddBooleans(ipp, IPP_TAG_OPERATION, "some-attribute", 10, values);
See Also
- ippAddBoolean()
,
-ippAddDate()
,
-ippAddInteger()
,
-ippAddIntegers()
, ippAddRange()
-, ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddDate()
,
+ippAddInteger()
,
+ippAddIntegers()
, ippAddRange()
+, ippAddRanges()
,
+ ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6202,11 +6178,11 @@ ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddDate()
function adds a single date-time
-attribute value to the specified IPP request.
+The ippAddDate()
function adds a single date-time
+ attribute value to the specified IPP request.
Example
#include <cups/ipp.h>
@@ -6217,16 +6193,16 @@ ippAddDate(ipp, IPP_TAG_OPERATION, "some-attribute",
ippTimeToDate(time(NULL));
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddInteger()
,
-ippAddIntegers()
, ippAddRange()
-, ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
-ippAddStrings()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddInteger()
,
+ippAddIntegers()
, ippAddRange()
+, ippAddRanges()
,
+ ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
+ippAddStrings()
,
ippTimeToDate()
@@ -6243,18 +6219,18 @@ ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group,
Argument Description
ipp The IPP request
group The IPP group
-tag The type of integer value (IPP_TAG_INTEGER or
-IPP_TAG_ENUM)
+tag The type of integer value (IPP_TAG_INTEGER or
+ IPP_TAG_ENUM)
name The name of attribute
value The integer value
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddInteger()
function adds a single integer
-attribute value to the specified IPP request.
+The ippAddInteger()
function adds a single integer
+ attribute value to the specified IPP request.
Example
#include <cups/ipp.h>
@@ -6264,15 +6240,15 @@ ipp_t *ipp;
ippAddInteger(ipp, IPP_TAG_OPERATION, "limit", 100);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
,
-ippAddIntegers()
, ippAddRange()
-, ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
,
+ippAddIntegers()
, ippAddRange()
+, ippAddRanges()
,
+ ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6289,21 +6265,21 @@ ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group,
Argument Description
ipp The IPP request
group The IPP group
-tag The type of integer value (IPP_TAG_INTEGER or
-IPP_TAG_ENUM)
+tag The type of integer value (IPP_TAG_INTEGER or
+ IPP_TAG_ENUM)
name The name of attribute
num_values The number of values
values The integer values
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddIntegers()
function adds one or more integer
-attribute values to the specified IPP request. If the values
- pointer is NULL
then an array of num_values
- 0 values is created.
+The ippAddIntegers()
function adds one or more integer
+ attribute values to the specified IPP request. If the values
+ pointer is NULL
then an array of num_values
0
+ values is created.
Example
#include <cups/ipp.h>
@@ -6314,15 +6290,15 @@ int values[100];
ippAddIntegers(ipp, IPP_TAG_OPERATION, "some-attribute", 100, values);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddRange()
,
-ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddRange()
,
+ ippAddRanges()
,
+ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6345,11 +6321,11 @@ ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddRange()
function adds a single range
-attribute value to the specified IPP request.
+The ippAddRange()
function adds a single range attribute
+ value to the specified IPP request.
Example
#include <cups/ipp.h>
@@ -6359,15 +6335,15 @@ ipp_t *ipp;
ippAddRange(ipp, IPP_TAG_OPERATION, "page-ranges", 1, 10);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddIntegers()
,
-ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddIntegers()
,
+ ippAddRanges()
,
+ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6391,13 +6367,13 @@ ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddRanges()
function adds one or more range
-attribute values to the specified IPP request. If the values
+
The ippAddRanges()
function adds one or more range
+ attribute values to the specified IPP request. If the values
pointer is NULL
then an array of num_values
- 0,0 ranges is created.
+ 0,0 ranges is created.
Example
#include <cups/ipp.h>
@@ -6409,15 +6385,15 @@ int highs[2];
ippAddRanges(ipp, IPP_TAG_OPERATION, "page-ranges", 2, lows, highs);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddIntegers()
,
-ippAddRange()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddIntegers()
,
+ ippAddRange()
,
+ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6441,11 +6417,11 @@ ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddResolution()
function adds a single
-resolution attribute value to the specified IPP request.
+The ippAddResolution()
function adds a single resolution
+ attribute value to the specified IPP request.
Example
#include <cups/ipp.h>
@@ -6456,15 +6432,15 @@ ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolution",
720, 720, IPP_RES_PER_INCH);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddIntegers()
,
-ippAddRange()
,
-ippAddRanges()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddIntegers()
,
+ ippAddRange()
,
+ippAddRanges()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6490,13 +6466,13 @@ ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddResolutions()
function adds one or more
-resolution attribute values to the specified IPP request. If the
+The ippAddResolutions()
function adds one or more
+ resolution attribute values to the specified IPP request. If the
values
pointer is NULL
then an array of
-num_values
0,0 resolutions is created.
+num_values
0,0 resolutions is created.
Example
#include <cups/ipp.h>
@@ -6510,15 +6486,15 @@ ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolutions-supported",
5, xres, yres, units);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddIntegers()
,
-ippAddRange()
,
-ippAddRanges()
,
-ippAddResolution()
,
-ippAddSeparator()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddIntegers()
,
+ ippAddRange()
,
+ippAddRanges()
,
+ippAddResolution()
,
+ippAddSeparator()
,
+ippAddString()
,
ippAddStrings()
@@ -6535,11 +6511,11 @@ ipp_attribute_t *ippAddSeparator(ipp_t *ipp);
Returns
-A pointer to the new separator or NULL if the separator could not be
-created.
+A pointer to the new separator or NULL if the separator could not be
+ created.
Description
-The ippAddSeparator()
function adds a group separator
-to the specified IPP request.
+The ippAddSeparator()
function adds a group separator to
+ the specified IPP request.
Example
#include <cups/ipp.h>
@@ -6549,15 +6525,15 @@ ipp_t *ipp;
ippAddSeparator(ipp);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddIntegers()
,
-ippAddRange()
,
-ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddString()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddIntegers()
,
+ ippAddRange()
,
+ippAddRanges()
,
+ippAddResolution()
,
+ippAddResolutions()
,
+ippAddString()
,
ippAddStrings()
@@ -6581,14 +6557,14 @@ ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddString()
function adds a single string
-attribute value to the specified IPP request. For IPP_TAG_NAMELANG
- and IPP_TAG_TEXTLANG
strings, the charset value is
-provided with the string to identify the string encoding used.
-Otherwise the charset value is ignored.
+The ippAddString()
function adds a single string
+ attribute value to the specified IPP request. For
+IPP_TAG_NAMELANG
and IPP_TAG_TEXTLANG
strings, the
+ charset value is provided with the string to identify the string
+ encoding used. Otherwise the charset value is ignored.
Example
#include <cups/ipp.h>
@@ -6599,15 +6575,15 @@ ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
NULL, "abc123");
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddIntegers()
,
-ippAddRange()
,
-ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddIntegers()
,
+ ippAddRange()
,
+ippAddRanges()
,
+ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
ippAddStrings()
@@ -6633,16 +6609,16 @@ ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group,
Returns
-A pointer to the new attribute or NULL if the attribute could not be
-created.
+A pointer to the new attribute or NULL if the attribute could not be
+ created.
Description
-The ippAddStrings()
function adds one or more string
-attribute values to the specified IPP request. For
-IPP_TAG_NAMELANG
and IPP_TAG_TEXTLANG
strings, the
-charset value is provided with the strings to identify the string
-encoding used. Otherwise the charset value is ignored. If the
+The ippAddStrings()
function adds one or more string
+ attribute values to the specified IPP request. For
+IPP_TAG_NAMELANG
and IPP_TAG_TEXTLANG
strings, the
+ charset value is provided with the strings to identify the string
+ encoding used. Otherwise the charset value is ignored. If the
values
pointer is NULL
then an array of
-num_values
NULL strings is created.
+num_values
NULL strings is created.
Example
#include <cups/ipp.h>
@@ -6654,15 +6630,15 @@ ippAddStrings(ipp, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "attr-name",
2, NULL, values);
See Also
- ippAddBoolean()
,
-ippAddBooleans()
,
-ippAddDate()
, ippAddInteger()
-, ippAddIntegers()
,
-ippAddRange()
,
-ippAddRanges()
,
-ippAddResolution()
,
-ippAddResolutions()
,
-ippAddSeparator()
,
+ ippAddBoolean()
,
+ ippAddBooleans()
,
+ippAddDate()
, ippAddInteger()
+, ippAddIntegers()
,
+ ippAddRange()
,
+ippAddRanges()
,
+ippAddResolution()
,
+ippAddResolutions()
,
+ippAddSeparator()
,
ippAddString()
@@ -6679,10 +6655,10 @@ time_t ippDateToTime(const ipp_uchar_t date[11]);
Returns
-A UNIX time value.
+A UNIX time value.
Description
-The ippDateToTime()
function converts an IPP date-time
-value to a UNIX time value.
+The ippDateToTime()
function converts an IPP date-time
+ value to a UNIX time value.
Example
#include <cups/ipp.h>
@@ -6692,7 +6668,7 @@ ipp_uchar_t date[11];
printf("UNIX time is %d\n", ippDateToTime(date));
See Also
- ippTimeToDate()
+ ippTimeToDate()
ippDelete()
@@ -6708,8 +6684,8 @@ void ippDelete(ipp_t *ipp);
Description
-The ippDelete()
function deletes all memory used by an
-IPP request or response.
+The ippDelete()
function deletes all memory used by an
+ IPP request or response.
Example
#include <cups/ipp.h>
@@ -6719,7 +6695,7 @@ ipp_t *ipp;
ippDelete(ipp);
See Also
- ippNew()
+ ippNew()
ippFindAttribute()
@@ -6734,19 +6710,19 @@ ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t tag);
ipp The IPP request or response
name The name of the attribute
tag The required value tag for the attribute or
- IPP_TAG_ZERO
for any type of value.
+IPP_TAG_ZERO
for any type of value.
Returns
A pointer to the first occurrence of the requested attribute, or
-NULL
if it was not found.
+NULL
if it was not found.
Description
-ippFindAttribute()
finds the first occurrence of the
-named attribute. The tag
parameter restricts the search to
-a specific value type - use IPP_TAG_ZERO
to find any value
-with the name.
+ippFindAttribute()
finds the first occurrence of the
+ named attribute. The tag
parameter restricts the search to
+ a specific value type - use IPP_TAG_ZERO
to find any value
+ with the name.
The value tags IPP_TAG_NAME
and IPP_TAG_TEXT
- match the name/text values with or without the language code.
+ match the name/text values with or without the language code.
Example
ipp_attribute_t *attr;
@@ -6754,9 +6730,9 @@ ipp_attribute_t *attr;
attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
See Also
- cupsDoFileRequest()
,
-cupsDoRequest()
, ippDelete()
-, ippNew()
+ cupsDoFileRequest()
,
+ cupsDoRequest()
,
+ippDelete()
, ippNew()
ippLength()
@@ -6772,16 +6748,16 @@ int ippLength(ipp_t *ipp);
Returns
-The total encoded length of the IPP request or response in bytes.
+The total encoded length of the IPP request or response in bytes.
Description
-ippLength()
returns the length of the IPP request or
-response in bytes.
+ippLength()
returns the length of the IPP request or
+ response in bytes.
Example
printf("The length of the response is %d bytes.\n", ippLength(response));
See Also
- ippDelete()
,
+ ippDelete()
,
ippNew()
@@ -6791,10 +6767,10 @@ ippNew()
ipp_t *ippNew(void);
Returns
-A pointer to a new IPP request or response.
+A pointer to a new IPP request or response.
Description
-The ippNew()
function creates a new IPP request or
-response.
+The ippNew()
function creates a new IPP request or
+ response.
Example
#include <cups/ipp.h>
@@ -6804,7 +6780,7 @@ ipp_t *ipp;
ipp = ippNew();
See Also
- ippDelete()
+ ippDelete()
ippPort()
@@ -6813,10 +6789,10 @@ ipp = ippNew();
int ippPort(void);
Returns
-The default TCP/IP port number for IPP requests.
+The default TCP/IP port number for IPP requests.
Description
-The ippPort()
function returns the default IPP port
-number for requests.
+The ippPort()
function returns the default IPP port
+ number for requests.
Example
#include <cups/http.h>
@@ -6827,8 +6803,8 @@ http_t *http;
http = httpConnect(cupsServer(), ippPort());
See Also
- cupsServer()
,
-ippSetPort()
+ cupsServer()
,
+ ippSetPort()
ippRead()
@@ -6845,12 +6821,12 @@ ipp_state_t ippRead(http_t *http, ipp_t *ipp);
Returns
-The current read state.
+The current read state.
Description
-The ippRead()
function reads IPP attributes from the
-specified HTTP connection. Programs should continue calling
+The ippRead()
function reads IPP attributes from the
+ specified HTTP connection. Programs should continue calling
ippRead()
until IPP_ERROR
or IPP_DATA
- is returned.
+ is returned.
Example
#include <cups/http.h>
@@ -6872,7 +6848,7 @@ if (status == IPP_DATA)
}
See Also
- ippWrite()
+ ippWrite()
ippSetPort()
@@ -6889,8 +6865,8 @@ ippSetPort(int port);
Description
-The ippSetPort()
function sets the default IPP port
-number for requests.
+The ippSetPort()
function sets the default IPP port
+ number for requests.
Example
#include <cups/http.h>
@@ -6901,7 +6877,7 @@ number for requests.
ippSetPort(8631);
See Also
- ippPort()
+ ippPort()
ippTimeToDate()
@@ -6917,10 +6893,10 @@ ipp_uchar_t *ippTimeToDate(time_t time);
Returns
-A static pointer to an IPP date-time value.
+A static pointer to an IPP date-time value.
Description
-The ippTimeToDate()
function converts a UNIX time to an
-IPP date-time value.
+The ippTimeToDate()
function converts a UNIX time to an
+ IPP date-time value.
Example
#include <cups/ipp.h>
@@ -6930,7 +6906,7 @@ ipp_uchar_t *date;
date = ippTimeToDate(time(NULL));
See Also
- ippDateToTime()
+ ippDateToTime()
ippWrite()
@@ -6947,12 +6923,12 @@ ipp_state_t ippWrite(http_t *http, ipp_t *ipp);
Returns
-The current write state.
+The current write state.
Description
-The ippWrite()
function writes IPP attributes to the
-specified HTTP connection. Programs should continue calling
+The ippWrite()
function writes IPP attributes to the
+ specified HTTP connection. Programs should continue calling
ippWrite()
until IPP_ERROR
or IPP_DATA
- is returned.
+ is returned.
Example
#include <cups/http.h>
@@ -6975,7 +6951,7 @@ if (status == IPP_DATA)
}
See Also
- ippRead()
+ ippRead()
ppdClose()
@@ -6991,8 +6967,8 @@ void ppdClose(ppd_file_t *ppd);
Description
-The ppdClose()
function frees all memory associated
-with the PPD file.
+The ppdClose()
function frees all memory associated with
+ the PPD file.
Example
#include <cups/ppd.h>
@@ -7002,8 +6978,8 @@ ppd_file_t *ppd;
ppdClose(ppd);
See Also
- ppdOpen()
,
-ppdOpenFd()
, ppdOpenFile()
+ ppdOpen()
,
+ppdOpenFd()
, ppdOpenFile()
@@ -7020,10 +6996,10 @@ int ppdConflicts(ppd_file_t *ppd);
Returns
-The number of option conflicts in the file.
+The number of option conflicts in the file.
Description
-The ppdConflicts()
function returns the number of
-conflicts with the currently selected options.
+The ppdConflicts()
function returns the number of
+ conflicts with the currently selected options.
Example
#include <cups/ppd.h>
@@ -7033,9 +7009,9 @@ ppd_file_t *ppd;
printf("%d conflicts\n", ppdConflicts(ppd));
See Also
- cupsMarkOptions()
,
-ppdIsMarked()
,
-ppdMarkDefaults()
,
+ cupsMarkOptions()
,
+ ppdIsMarked()
,
+ppdMarkDefaults()
,
ppdMarkOption()
@@ -7054,10 +7030,10 @@ int ppdEmit(ppd_file_t *ppd, FILE *file, ppd_section_t section);
Returns
-0 on success, -1 on error.
+0 on success, -1 on error.
Description
-The ppdEmit()
function sends printer-specific option
-commands to the specified file.
+The ppdEmit()
function sends printer-specific option
+ commands to the specified file.
Example
#include <cups/ppd.h>
@@ -7067,7 +7043,7 @@ ppd_file_t *ppd;
ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
See Also
- ppdEmitFd()
+ ppdEmitFd()
ppdEmitFd()
@@ -7085,10 +7061,10 @@ int ppdEmitFd(ppd_file_t *ppd, int fd, ppd_section_t section);
Returns
-0 on success, -1 on error.
+0 on success, -1 on error.
Description
-The ppdEmitFd()
function sends printer-specific option
-commands to the specified file descriptor.
+The ppdEmitFd()
function sends printer-specific option
+ commands to the specified file descriptor.
Example
#include <cups/ppd.h>
@@ -7098,7 +7074,7 @@ ppd_file_t *ppd;
ppdEmitFd(ppd, 1, PPD_ORDER_PAGE);
See Also
- ppdEmit()
+ ppdEmit()
ppdFindChoice()
@@ -7115,10 +7091,10 @@ ppd_choice_t *ppdFindChoice(ppd_option_t *option, const char *choice);
Returns
-A pointer to the choice data or NULL if the choice does not exist.
+A pointer to the choice data or NULL if the choice does not exist.
Description
-The ppdFindChoice()
function returns a pointer to the
-choice data for the specified option.
+The ppdFindChoice()
function returns a pointer to the
+ choice data for the specified option.
Example
#include <cups/ppd.h>
@@ -7131,8 +7107,8 @@ option = ppdFindOption(ppd, "PageSize");
choice = ppdFindChoice(option, "Letter");
See Also
- ppdFindMarkedChoice()
, ppdFindOption()
+ ppdFindMarkedChoice()
, ppdFindOption()
ppdFindMarkedChoice()
@@ -7149,11 +7125,11 @@ ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword);
Returns
-A pointer to the choice data or NULL if the choice does not exist or
-is not marked.
+A pointer to the choice data or NULL if the choice does not exist or
+ is not marked.
Description
-The ppdFindMarkedChoice()
function returns a pointer to
-the marked choice data for the specified option.
+The ppdFindMarkedChoice()
function returns a pointer to
+ the marked choice data for the specified option.
Example
#include <cups/ppd.h>
@@ -7164,8 +7140,8 @@ ppd_choice_t *choice;
choice = ppdFindMarkedChoice(ppd, "PageSize");
See Also
- ppdFindChoice()
,
-ppdFindOption()
+ ppdFindChoice()
,
+ ppdFindOption()
ppdFindOption()
@@ -7182,10 +7158,10 @@ ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword);
Returns
-A pointer to the option data or NULL if the option does not exist.
+A pointer to the option data or NULL if the option does not exist.
Description
-The ppdFindOption()
function returns a pointer to the
-option data for the specified option.
+The ppdFindOption()
function returns a pointer to the
+ option data for the specified option.
Example
#include <cups/ppd.h>
@@ -7196,8 +7172,8 @@ ppd_option_t *option;
option = ppdFindOption(ppd, "PageSize");
See Also
- ppdFindChoice()
,
-ppdFindMarkedChoice()
+ ppdFindChoice()
,
+ ppdFindMarkedChoice()
ppdIsMarked()
@@ -7215,10 +7191,10 @@ int ppdIsMarked(ppd_file_t *ppd, const char *keyword, char char *choice);
Returns
-1 if the choice is marked, 0 otherwise.
+1 if the choice is marked, 0 otherwise.
Description
-The ppdIsMarked()
function returns whether or not the
-specified option choice is marked.
+The ppdIsMarked()
function returns whether or not the
+ specified option choice is marked.
Example
#include <cups/ppd.h>
@@ -7229,10 +7205,10 @@ printf("Letter size %s selected.\n",
ppdIsMarked(ppd, "PageSize", "Letter") ? "is" : "is not");
See Also
- cupsMarkOptions()
,
-ppdConflicts()
,
-ppdIsMarked()
,
-ppdMarkDefaults()
,
+ cupsMarkOptions()
,
+ ppdConflicts()
,
+ppdIsMarked()
,
+ppdMarkDefaults()
,
ppdMarkOption()
@@ -7249,8 +7225,8 @@ void ppdMarkDefaults(ppd_file_t *ppd);
Description
-The ppdMarkDefaults()
function marks all of the default
-choices in the PPD file.
+The ppdMarkDefaults()
function marks all of the default
+ choices in the PPD file.
Example
#include <cups/ppd.h>
@@ -7260,10 +7236,10 @@ ppd_file_t *ppd;
ppdMarkDefaults(ppd);
See Also
- cupsMarkOptions()
,
-ppdConflicts()
,
-ppdIsMarked()
,
-ppdMarkDefaults()
,
+ cupsMarkOptions()
,
+ ppdConflicts()
,
+ppdIsMarked()
,
+ppdMarkDefaults()
,
ppdMarkOption()
@@ -7282,10 +7258,10 @@ int ppdMarkOption(ppd_file_t *ppd, const char *keyword, const char *choice);
Returns
-The number of conflicts in the PPD file.
+The number of conflicts in the PPD file.
Description
-The ppdMarkOption()
function marks the specified option
-choice.
+The ppdMarkOption()
function marks the specified option
+ choice.
Example
#include <cups/ppd.h>
@@ -7295,10 +7271,10 @@ ppd_file_t *ppd;
ppdMarkOption(ppd, "PageSize", "Letter");
See Also
- cupsMarkOptions()
,
-ppdConflicts()
,
-ppdIsMarked()
,
-ppdMarkDefaults()
,
+ cupsMarkOptions()
,
+ ppdConflicts()
,
+ppdIsMarked()
,
+ppdMarkDefaults()
,
ppdMarkOption()
@@ -7315,11 +7291,11 @@ ppd_file_t *ppdOpen(FILE *file);
Returns
-A pointer to a PPD file structure or NULL if the PPD file could not
-be read.
+A pointer to a PPD file structure or NULL if the PPD file could not
+ be read.
Description
-The ppdOpen()
function reads a PPD file from the
-specified file into memory.
+The ppdOpen()
function reads a PPD file from the
+ specified file into memory.
Example
#include <cups/ppd.h>
@@ -7332,8 +7308,8 @@ ppd = ppdOpen(file);
fclose(file);
See Also
- ppdClose()
,
-ppdOpenFd()
, ppdOpenFile()
+ ppdClose()
,
+ppdOpenFd()
, ppdOpenFile()
@@ -7350,11 +7326,11 @@ ppd_file_t *ppdOpenFd(int fd);
Returns
-A pointer to a PPD file structure or NULL if the PPD file could not
-be read.
+A pointer to a PPD file structure or NULL if the PPD file could not
+ be read.
Description
-The ppdOpenFd()
function reads a PPD file from the
-specified file descriptor into memory.
+The ppdOpenFd()
function reads a PPD file from the
+ specified file descriptor into memory.
Example
#include <cups/ppd.h>
@@ -7367,11 +7343,10 @@ ppd = ppdOpenFd(fd);
close(fd);
See Also
- ppdClose()
,
-ppdOpen()
, ppdOpenFile()
+ ppdClose()
,
+ppdOpen()
, ppdOpenFile()
-
ppdOpenFile()
Usage
@@ -7385,11 +7360,11 @@ ppd_file_t *ppdOpenFile(const char *filename);
Returns
-A pointer to a PPD file structure or NULL if the PPD file could not
-be read.
+A pointer to a PPD file structure or NULL if the PPD file could not
+ be read.
Description
-The ppdOpenFile()
function reads a PPD file from the
-named file into memory.
+The ppdOpenFile()
function reads a PPD file from the
+ named file into memory.
Example
#include <cups/ppd.h>
@@ -7399,8 +7374,8 @@ ppd_file_t *ppd;
ppd = ppdOpenFile("filename.ppd");
See Also
- ppdClose()
,
-ppdOpen()
, ppdOpenFd()
+ ppdClose()
,
+ppdOpen()
, ppdOpenFd()
ppdPageLength()
@@ -7417,11 +7392,11 @@ float ppdPageLength(ppd_file_t *ppd, const char *name);
Returns
-The length of the specified page size in points or 0 if the page
-size does not exist.
+The length of the specified page size in points or 0 if the page size
+ does not exist.
Description
-The ppdPageLength()
function returns the page length of
-the specified page size.
+The ppdPageLength()
function returns the page length of
+ the specified page size.
Example
#include <cups/ppd.h>
@@ -7431,8 +7406,8 @@ ppd_file_t *ppd;
printf("Length = %.0f\n", ppdPageLength(ppd, "Letter"));
See Also
- ppdPageLength()
,
-ppdPageSize()
,
+ ppdPageLength()
,
+ ppdPageSize()
,
ppdPageWidth()
@@ -7450,11 +7425,11 @@ ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name);
Returns
-A pointer to the page size record of the specified page size in
-points or NULL if the page size does not exist.
+A pointer to the page size record of the specified page size in
+ points or NULL if the page size does not exist.
Description
-The ppdPageSize()
function returns the page size record
-for the specified page size.
+The ppdPageSize()
function returns the page size record
+ for the specified page size.
Example
#include <cups/ppd.h>
@@ -7474,8 +7449,8 @@ if (size != NULL)
}
See Also
- ppdPageLength()
,
-ppdPageWidth()
+ ppdPageLength()
,
+ ppdPageWidth()
ppdPageWidth()
@@ -7492,11 +7467,11 @@ float ppdPageWidth(ppd_file_t *ppd, const char *name);
Returns
-The width of the specified page size in points or 0 if the page size
-does not exist.
+The width of the specified page size in points or 0 if the page size
+ does not exist.
Description
-The ppdPageWidth()
function returns the page width of
-the specified page size.
+The ppdPageWidth()
function returns the page width of
+ the specified page size.
Example
#include <cups/ppd.h>
@@ -7506,6 +7481,6 @@ ppd_file_t *ppd;
printf("Width = %.0f\n", ppdPageWidth(ppd, "Letter"));
See Also
- ppdPageLength()
,
-ppdPageSize()
+ ppdPageLength()
,
+ ppdPageSize()
diff --git a/doc/spm.pdf b/doc/spm.pdf
index 672132355a..50d39b1efb 100644
Binary files a/doc/spm.pdf and b/doc/spm.pdf differ
diff --git a/doc/spm.shtml b/doc/spm.shtml
index 55bf517bb3..94dbb01262 100644
--- a/doc/spm.shtml
+++ b/doc/spm.shtml
@@ -1,7 +1,7 @@
-
+
CUPS Software Programmers Manual
@@ -11,7 +11,7 @@
This software programmers manual provides software
programming information for the Common UNIX Printing System
-("CUPS") Version 1.1.7.
+("CUPS") Version 1.2.0.
2 References
2.1 CUPS Documentation
-The following CUPS documentation is referenced by this document:
+The following CUPS documentation is referenced by this document:
-- CUPS-CMP-1.1: CUPS Configuration Management Plan
-- CUPS-IDD-1.1: CUPS System Interface Design Description
-- CUPS-IPP-1.1: CUPS Implementation of IPP
-- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
-- CUPS-SDD-1.1: CUPS Software Design Description
-- CUPS-SPM-1.1.x: CUPS Software Programming Manual
-- CUPS-SSR-1.1: CUPS Software Security Report
-- CUPS-STP-1.1: CUPS Software Test Plan
-- CUPS-SUM-1.1.x: CUPS Software Users Manual
-- CUPS-SVD-1.1: CUPS Software Version Description
+- CUPS-CMP-1.1: CUPS Configuration Management Plan
+- CUPS-IDD-1.1: CUPS System Interface Design Description
+- CUPS-IPP-1.1: CUPS Implementation of IPP
+- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
+- CUPS-SDD-1.1: CUPS Software Design Description
+- CUPS-SPM-1.1.x: CUPS Software Programming Manual
+- CUPS-SSR-1.1: CUPS Software Security Report
+- CUPS-STP-1.1: CUPS Software Test Plan
+- CUPS-SUM-1.1.x: CUPS Software Users Manual
+- CUPS-SVD-1.1: CUPS Software Version Description
2.2 Other Documents
-The following non-CUPS documents are referenced by this document:
+The following non-CUPS documents are referenced by this document:
-
-Adobe PostScript Printer Description File Format Specification,
- Version 4.3.
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.
-Adobe PostScript Language Reference, Third Edition.
-IPP: Job and Printer Set Operations
-IPP/1.1: Encoding and Transport
-IPP/1.1: Implementers Guide
-IPP/1.1: Model and Semantics
-RFC 1179, Line
-Printer Daemon Protocol
-RFC 2567, Design
-Goals for an Internet Printing Protocol
-RFC 2568, Rationale
-for the Structure of the Model and Protocol for the Internet
-Printing Protocol
-RFC 2569, Mapping
-between LPD and IPP Protocols
-RFC 2616, Hypertext
-Transfer Protocol -- HTTP/1.1
-RFC 2617, HTTP
-Authentication: Basic and Digest Access Authentication
+Adobe PostScript Language Reference, Third Edition.
+IPP: Job and Printer Set Operations
+IPP/1.1: Encoding and Transport
+IPP/1.1: Implementers Guide
+IPP/1.1: Model and Semantics
+RFC 1179, Line Printer
+ Daemon Protocol
+RFC 2567, Design Goals
+ for an Internet Printing Protocol
+RFC 2568, Rationale
+ for the Structure of the Model and Protocol for the Internet
+ Printing Protocol
+RFC 2569, Mapping
+ between LPD and IPP Protocols
+RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1
+RFC 2617, HTTP
+ Authentication: Basic and Digest Access Authentication
3 Programs
-The following table describes the average memory, disk, and CPU
-usage of each program in CUPS.
-The base memory column shows the initial memory requirements for
-each program, including any shared libraries that are provided by CUPS.
-The max memory column shows the maximum amount of memory that will
-be used by the program based upon the default configuration settings
-supplied with CUPS.
-The temp files column indicates whether any temporary files are
-created.
-The CPU usage column specifies a relative CPU usage by the program
-under normal conditions, either low, medium, or high. Low usage
-indicates that the program will never use more than 33% of the
-available CPU time. Medium usage indicates the program will use as much
-as 66% of the available CPU time. High usage indicates the program uses
-66% or more of the available CPU time.
+
The following table describes the average memory, disk, and CPU usage
+ of each program in CUPS.
+The base memory column shows the initial memory requirements for each
+ program, including any shared libraries that are provided by CUPS.
+The max memory column shows the maximum amount of memory that will be
+ used by the program based upon the default configuration settings
+ supplied with CUPS.
+The temp files column indicates whether any temporary files are
+ created.
+The CPU usage column specifies a relative CPU usage by the program
+ under normal conditions, either low, medium, or high. Low usage
+ indicates that the program will never use more than 33% of the
+ available CPU time. Medium usage indicates the program will use as much
+ as 66% of the available CPU time. High usage indicates the program uses
+ 66% or more of the available CPU time.
Backends
-Program Base Memory Max Memory Temp
-Files CPU Usage
+Program Base Memory Max Memory Temp
+ Files CPU Usage
ipp 91k 256k Up to size of print file
Low
lpd 89k 89k Up to size of print file
Low
-parallel 85k 85k Up to size of print
-file Low
+parallel 85k 85k Up to size of print
+ file Low
serial 85k 85k Up to size of print file
Low
socket 85k 85k Up to size of print file
@@ -158,10 +158,10 @@ Low
usb 85k 85k Up to size of print file
Low
CGIs
-Program Base Memory Max Memory Temp
-Files CPU Usage
-admin.cgi 107k 256k Up to size of PPD
-file Medium
+Program Base Memory Max Memory Temp
+ Files CPU Usage
+admin.cgi 107k 256k Up to size of PPD
+ file Medium
classes.cgi 95k Size of class objects
None Medium
jobs.cgi 93k Size of job objects None
@@ -169,8 +169,8 @@ Medium
printers.cgi 95k Size of printer objects
None Medium
Command-Line Programs
-Program Base Memory Max Memory Temp
-Files CPU Usage
+Program Base Memory Max Memory Temp
+ Files CPU Usage
accept 88k 128k None Low
cancel 88k 128k None Low
disable 88k 128k None Low
@@ -188,31 +188,31 @@ NoneMedium
Medium
lpr 87k 256k None Low
lprm 84k 128k None Low
-lpstat 119k Size of job, printer, and class
-objects None Medium
+lpstat 119k Size of job, printer, and class
+ objects None Medium
reject 88k 128k None Low
Daemons
-Program Base Memory Max Memory Temp
-Files CPU Usage
-cups-lpd 92k 256k One file per control
-or data file from client Low
+Program Base Memory Max Memory Temp
+ Files CPU Usage
+cups-lpd 92k 256k One file per control
+ or data file from client Low
cupsd 308k See Scheduler Requirements
See Scheduler Requirements Medium
cups-polld 84k Size of printer and class objects
None Low
Filters
-Program Base Memory Max Memory Temp
-Files CPU Usage
+Program Base Memory Max Memory Temp
+ Files CPU Usage
hpgltops 263k 320k None Medium
-imagetops 628k 10M Swap file for
-uncompressed image data Medium
-imagetoraster 652k 10M Swap file for
-uncompressed image data High
-pstops 775k 840k Up to size of print
-file Medium
-pstoraster 4M 14M Swap file for command
-lists High
+imagetops 628k 10M Swap file for
+ uncompressed image data Medium
+imagetoraster 652k 10M Swap file for
+ uncompressed image data High
+pstops 775k 840k Up to size of print
+ file Medium
+pstoraster 4M 14M Swap file for command
+ lists High
rastertoepson 693k 1M None Low
rastertohp 690k 1M None Low
@@ -222,11 +222,11 @@ Low
4 Scheduler Objects
-The cupsd
program is the CUPS scheduler process. It
-manages many interdependent server objects that are used to manage and
-print files to printers.
-The following table provides the memory and disk cost associated
-with each server object.
+
The cupsd
program is the CUPS scheduler process. It
+ manages many interdependent server objects that are used to manage and
+ print files to printers.
+The following table provides the memory and disk cost associated with
+ each server object.
Object Memory Per Disk Per
@@ -249,49 +249,49 @@ with each server object.
A Glossary
A.1 Terms
-- C
-- A computer language.
-- parallel
-- Sending or receiving data more than 1 bit at a time.
-- pipe
-- A one-way communications channel between two programs.
-- serial
-- Sending or receiving data 1 bit at a time.
-- socket
-- A two-way network communications channel.
+- C
+- A computer language.
+- parallel
+- Sending or receiving data more than 1 bit at a time.
+- pipe
+- A one-way communications channel between two programs.
+- serial
+- Sending or receiving data 1 bit at a time.
+- socket
+- A two-way network communications channel.
A.2 Acronyms
-- ASCII
-- American Standard Code for Information Interchange
-- CUPS
-- Common UNIX Printing System
-- ESC/P
-- EPSON Standard Code for Printers
-- FTP
-- File Transfer Protocol
-- HP-GL
-- Hewlett-Packard Graphics Language
-- HP-PCL
-- Hewlett-Packard Page Control Language
-- HP-PJL
-- Hewlett-Packard Printer Job Language
-- IETF
-- Internet Engineering Task Force
-- IPP
-- Internet Printing Protocol
-- ISO
-- International Standards Organization
-- LPD
-- Line Printer Daemon
-- MIME
-- Multimedia Internet Mail Exchange
-- PPD
-- PostScript Printer Description
-- SMB
-- Server Message Block
-- TFTP
-- Trivial File Transfer Protocol
+- ASCII
+- American Standard Code for Information Interchange
+- CUPS
+- Common UNIX Printing System
+- ESC/P
+- EPSON Standard Code for Printers
+- FTP
+- File Transfer Protocol
+- HP-GL
+- Hewlett-Packard Graphics Language
+- HP-PCL
+- Hewlett-Packard Page Control Language
+- HP-PJL
+- Hewlett-Packard Printer Job Language
+- IETF
+- Internet Engineering Task Force
+- IPP
+- Internet Printing Protocol
+- ISO
+- International Standards Organization
+- LPD
+- Line Printer Daemon
+- MIME
+- Multimedia Internet Mail Exchange
+- PPD
+- PostScript Printer Description
+- SMB
+- Server Message Block
+- TFTP
+- Trivial File Transfer Protocol
diff --git a/doc/sps.pdf b/doc/sps.pdf
index 79527d3fb5..888366894c 100644
Binary files a/doc/sps.pdf and b/doc/sps.pdf differ
diff --git a/doc/ssr.html b/doc/ssr.html
index f06bfd2216..8171ad8821 100644
--- a/doc/ssr.html
+++ b/doc/ssr.html
@@ -1,27 +1,27 @@
- CUPS Software Security Report
+CUPS Software Security Report
-
- CUPS Software Security Report
+
+CUPS Software Security Report
CUPS-SSR-1.1
Easy Software Products
Copyright 1997-2001, All Rights Reserved
@@ -57,28 +57,28 @@ Copyright 1997-2001, All Rights Reserved
1 Scope
1.1 Identification
-This software security report provides an analysis of possible
-security concerns for the Common UNIX Printing System ("CUPS") Version
-1.1.
+This software security report provides an analysis of possible
+ security concerns for the Common UNIX Printing System ("CUPS") Version
+ 1.1.
1.2 System Overview
-CUPS provides a portable printing layer for UNIX®-based operating
-systems. It has been developed by Easy
-Software Products to promote a standard printing solution for all
-UNIX vendors and users. CUPS provides the System V and Berkeley
-command-line interfaces.
-CUPS uses the Internet Printing Protocol ("IPP") as the basis for
-managing print jobs and queues. The Line Printer Daemon ("LPD") Server
-Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
-also supported with reduced functionality. CUPS adds network printer
-browsing and PostScript Printer Description ("PPD") based printing
-options to support real-world printing under UNIX.
-CUPS also includes a customized version of GNU Ghostscript
-(currently based off GNU Ghostscript 5.50) and an image file RIP that
-are used to support non-PostScript printers. Sample drivers for HP and
-EPSON printers are included that use these filters.
+CUPS provides a portable printing layer for UNIX®-based operating
+ systems. It has been developed by Easy
+ Software Products to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.
+CUPS uses the Internet Printing Protocol ("IPP") as the basis for
+ managing print jobs and queues. The Line Printer Daemon ("LPD") Server
+ Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description ("PPD") based printing
+ options to support real-world printing under UNIX.
+CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.
1.3 Document Overview
-This software security report is organized into the following
-sections:
+This software security report is organized into the following
+ sections:
- 1 - Scope
- 2 - References
@@ -88,183 +88,182 @@ sections:
2 References
2.1 CUPS Documentation
-The following CUPS documentation is referenced by this document:
+The following CUPS documentation is referenced by this document:
-- CUPS-CMP-1.1: CUPS Configuration Management Plan
-- CUPS-IDD-1.1: CUPS System Interface Design Description
-- CUPS-IPP-1.1: CUPS Implementation of IPP
-- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
-- CUPS-SDD-1.1: CUPS Software Design Description
-- CUPS-SPM-1.1.x: CUPS Software Programming Manual
-- CUPS-SSR-1.1: CUPS Software Security Report
-- CUPS-STP-1.1: CUPS Software Test Plan
-- CUPS-SUM-1.1.x: CUPS Software Users Manual
-- CUPS-SVD-1.1: CUPS Software Version Description
+- CUPS-CMP-1.1: CUPS Configuration Management Plan
+- CUPS-IDD-1.1: CUPS System Interface Design Description
+- CUPS-IPP-1.1: CUPS Implementation of IPP
+- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
+- CUPS-SDD-1.1: CUPS Software Design Description
+- CUPS-SPM-1.1.x: CUPS Software Programming Manual
+- CUPS-SSR-1.1: CUPS Software Security Report
+- CUPS-STP-1.1: CUPS Software Test Plan
+- CUPS-SUM-1.1.x: CUPS Software Users Manual
+- CUPS-SVD-1.1: CUPS Software Version Description
2.2 Other Documents
-The following non-CUPS documents are referenced by this document:
+The following non-CUPS documents are referenced by this document:
-
-Adobe PostScript Printer Description File Format Specification,
- Version 4.3.
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.
-
-Adobe PostScript Language Reference, Third Edition.
-- IPP: Job and Printer Set Operations
-- IPP/1.1: Encoding and Transport
-- IPP/1.1: Implementers Guide
-- IPP/1.1: Model and Semantics
-- RFC 1179, Line
-Printer Daemon Protocol
-- RFC 2567, Design
-Goals for an Internet Printing Protocol
-- RFC 2568, Rationale
-for the Structure of the Model and Protocol for the Internet
-Printing Protocol
-- RFC 2569, Mapping
-between LPD and IPP Protocols
-- RFC 2616, Hypertext
-Transfer Protocol -- HTTP/1.1
-- RFC 2617, HTTP
-Authentication: Basic and Digest Access Authentication
+Adobe PostScript Language Reference, Third Edition.
+- IPP: Job and Printer Set Operations
+- IPP/1.1: Encoding and Transport
+- IPP/1.1: Implementers Guide
+- IPP/1.1: Model and Semantics
+- RFC 1179, Line Printer
+ Daemon Protocol
+- RFC 2567, Design Goals
+ for an Internet Printing Protocol
+- RFC 2568, Rationale
+ for the Structure of the Model and Protocol for the Internet
+ Printing Protocol
+- RFC 2569, Mapping
+ between LPD and IPP Protocols
+- RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1
+- RFC 2617, HTTP
+ Authentication: Basic and Digest Access Authentication
3 Local Access Risks
-Local access risks are those that can be exploited only with a local
-user account. This section does not address issues related to
-dissemination of the root password or other security issues associated
-with the UNIX operating system.
+Local access risks are those that can be exploited only with a local
+ user account. This section does not address issues related to
+ dissemination of the root password or other security issues associated
+ with the UNIX operating system.
3.1 Security Breaches
-There is one known security vulnerability with local access:
+There is one known security vulnerability with local access:
-- Device URIs are passed to backend filters in argv[0] and in an
-environment variable. Since device URIs can contain usernames and
-passwords it may be possible for a local user to gain access to a
-remote resource.
-We recommend that any password-protected accounts used for remote
-printing have limited access priviledges so that the possible damages
-can be minimized.
-The device URI is "sanitized" (the username and password are
- removed) when sent to an IPP client so that a remote user cannot
-exploit this vulnerability.
+- Device URIs are passed to backend filters in argv[0] and in an
+ environment variable. Since device URIs can contain usernames and
+ passwords it may be possible for a local user to gain access to a
+ remote resource.
+We recommend that any password-protected accounts used for remote
+ printing have limited access priviledges so that the possible damages
+ can be minimized.
+The device URI is "sanitized" (the username and password are removed)
+ when sent to an IPP client so that a remote user cannot exploit this
+ vulnerability.
4 Remote Access Risks
-Remote access risks are those that can be exploited without a local
-user account and/or from a remote system. This section does not address
-issues related to network or firewall security.
+Remote access risks are those that can be exploited without a local
+ user account and/or from a remote system. This section does not address
+ issues related to network or firewall security.
4.1 Denial of Service Attacks
-Like all Internet services, the CUPS server is vulnerable to denial
-of service attacks, including:
+Like all Internet services, the CUPS server is vulnerable to denial
+ of service attacks, including:
-- Establishing multiple connections to the server until the server
- will accept no more.
-This cannot be protected against by the current software. It is
-possible that future versions of the CUPS software could be configured
-to limit the number of connections allowed from a single host, however
-that still would not prevent a distributed attack.
-- Repeatedly opening and closing connections to the server as fast
- as possible.
-There is no easy way of protecting against this in the CUPS
- software. If the attack is coming from outside the local network it
-might be possible to filter such an attack, however once the
-connection request has been received by the server it must at least
-accept the connection to find out who is connecting.
-- Flooding the network with broadcast packets on port 631.
-It might be possible to disable browsing if this condition is
-detected by the CUPS software, however if there are large numbers of
-printers available on the network such an algorithm might think that
-an attack was occurring when instead a valid update was being
-received.
-- Sending partial IPP requests; specifically, sending part of an
- attribute value and then stopping transmission.
-The current code is structured to read and write the IPP request
-data on-the-fly, so there is no easy way to protect against this for
-large attribute values.
-- Sending large/long print jobs to printers, preventing other users
- from printing.
-There are limited facilities for protecting against large print
- jobs (the MaxRequestSize
attribute), however this will
- not protect printers from malicious users and print files that
- generate hundreds or thousands of pages. In general, we recommend
- restricting printer access to known hosts or networks, and adding
- user-level access control as needed for expensive printers.
+- Establishing multiple connections to the server until the server
+ will accept no more.
+This cannot be protected against by the current software. It is
+ possible that future versions of the CUPS software could be configured
+ to limit the number of connections allowed from a single host, however
+ that still would not prevent a distributed attack.
+- Repeatedly opening and closing connections to the server as fast as
+ possible.
+There is no easy way of protecting against this in the CUPS software.
+ If the attack is coming from outside the local network it might be
+ possible to filter such an attack, however once the connection request
+ has been received by the server it must at least accept the connection
+ to find out who is connecting.
+- Flooding the network with broadcast packets on port 631.
+It might be possible to disable browsing if this condition is
+ detected by the CUPS software, however if there are large numbers of
+ printers available on the network such an algorithm might think that an
+ attack was occurring when instead a valid update was being received.
+- Sending partial IPP requests; specifically, sending part of an
+ attribute value and then stopping transmission.
+The current code is structured to read and write the IPP request data
+ on-the-fly, so there is no easy way to protect against this for large
+ attribute values.
+- Sending large/long print jobs to printers, preventing other users
+ from printing.
+There are limited facilities for protecting against large print jobs
+ (the MaxRequestSize
attribute), however this will not
+ protect printers from malicious users and print files that generate
+ hundreds or thousands of pages. In general, we recommend restricting
+ printer access to known hosts or networks, and adding user-level access
+ control as needed for expensive printers.
4.2 Security Breaches
-The current CUPS server supports Basic, Digest, and local
-certificate authentication:
+The current CUPS server supports Basic, Digest, and local certificate
+ authentication:
-- Basic authentication essentially places the clear text of the
-username and password on the network. Since CUPS uses the UNIX
-username and password account information, the authentication
-information could be used to gain access to accounts (possibly
-priviledged accounts) on the server.
-- Digest authentication uses an MD5 checksum of the username,
- password, and domain ("CUPS"), so the original username and password
-is not sent over the network. However, the current implementation does
-not authenticate the entire message and uses the client's IP address
-for the nonce value, making it possible to launch "man in the middle"
-and replay attacks from the same client. The next minor release of
-CUPS will support Digest authentication of the entire message body,
-effectively stopping these methods of attack.
-- Local certificate authentication passes 128-bit "certificates"
-that identify an authenticated user. Certificates are created
-on-the-fly from random data and stored in files under
-/etc/cups/certs
. They have restricted read permissions: root +
-system for the root certificate, and lp + system for CGI certificates.
-Because certificates are only available on the local system, the CUPS
- server does not accept local authentication unless the client is
-connected to the localhost address (127.0.0.1.)
+- Basic authentication essentially places the clear text of the
+ username and password on the network. Since CUPS uses the UNIX username
+ and password account information, the authentication information could
+ be used to gain access to accounts (possibly priviledged accounts) on
+ the server.
+- Digest authentication uses an MD5 checksum of the username,
+ password, and domain ("CUPS"), so the original username and password is
+ not sent over the network. However, the current implementation does not
+ authenticate the entire message and uses the client's IP address for
+ the nonce value, making it possible to launch "man in the middle" and
+ replay attacks from the same client. The next minor release of CUPS
+ will support Digest authentication of the entire message body,
+ effectively stopping these methods of attack.
+- Local certificate authentication passes 128-bit "certificates" that
+ identify an authenticated user. Certificates are created on-the-fly
+ from random data and stored in files under
/etc/cups/certs
+. They have restricted read permissions: root + system for the root
+ certificate, and lp + system for CGI certificates. Because certificates
+ are only available on the local system, the CUPS server does not accept
+ local authentication unless the client is connected to the localhost
+ address (127.0.0.1.)
-The default CUPS configuration disables remote administration. We do
-not recommend that remote administration be enabled for all hosts.
-However, if you have a trusted network or subnet, access can be
-restricted accordingly. Also, we highly recommend using Digest
-authentication when possible. Unfortunately, most web browsers do not
-support Digest authentication at this time.
+The default CUPS configuration disables remote administration. We do
+ not recommend that remote administration be enabled for all hosts.
+ However, if you have a trusted network or subnet, access can be
+ restricted accordingly. Also, we highly recommend using Digest
+ authentication when possible. Unfortunately, most web browsers do not
+ support Digest authentication at this time.
A Glossary
A.1 Terms
-- C
-- A computer language.
-- parallel
-- Sending or receiving data more than 1 bit at a time.
-- pipe
-- A one-way communications channel between two programs.
-- serial
-- Sending or receiving data 1 bit at a time.
-- socket
-- A two-way network communications channel.
+- C
+- A computer language.
+- parallel
+- Sending or receiving data more than 1 bit at a time.
+- pipe
+- A one-way communications channel between two programs.
+- serial
+- Sending or receiving data 1 bit at a time.
+- socket
+- A two-way network communications channel.
A.2 Acronyms
-- ASCII
-- American Standard Code for Information Interchange
-- CUPS
-- Common UNIX Printing System
-- ESC/P
-- EPSON Standard Code for Printers
-- FTP
-- File Transfer Protocol
-- HP-GL
-- Hewlett-Packard Graphics Language
-- HP-PCL
-- Hewlett-Packard Page Control Language
-- HP-PJL
-- Hewlett-Packard Printer Job Language
-- IETF
-- Internet Engineering Task Force
-- IPP
-- Internet Printing Protocol
-- ISO
-- International Standards Organization
-- LPD
-- Line Printer Daemon
-- MIME
-- Multimedia Internet Mail Exchange
-- PPD
-- PostScript Printer Description
-- SMB
-- Server Message Block
-- TFTP
-- Trivial File Transfer Protocol
+- ASCII
+- American Standard Code for Information Interchange
+- CUPS
+- Common UNIX Printing System
+- ESC/P
+- EPSON Standard Code for Printers
+- FTP
+- File Transfer Protocol
+- HP-GL
+- Hewlett-Packard Graphics Language
+- HP-PCL
+- Hewlett-Packard Page Control Language
+- HP-PJL
+- Hewlett-Packard Printer Job Language
+- IETF
+- Internet Engineering Task Force
+- IPP
+- Internet Printing Protocol
+- ISO
+- International Standards Organization
+- LPD
+- Line Printer Daemon
+- MIME
+- Multimedia Internet Mail Exchange
+- PPD
+- PostScript Printer Description
+- SMB
+- Server Message Block
+- TFTP
+- Trivial File Transfer Protocol
diff --git a/doc/ssr.pdf b/doc/ssr.pdf
index f24244cd93..6dccf74de4 100644
Binary files a/doc/ssr.pdf and b/doc/ssr.pdf differ
diff --git a/doc/stp.html b/doc/stp.html
index 2ed71e25a0..bd95c89807 100644
--- a/doc/stp.html
+++ b/doc/stp.html
@@ -1,27 +1,27 @@
- CUPS Software Test Plan
+CUPS Software Test Plan
-
- CUPS Software Test Plan
+
+CUPS Software Test Plan
CUPS-STP-1.1
Easy Software Products
Copyright 1997-2001, All Rights Reserved
@@ -68,27 +68,27 @@ Copyright 1997-2001, All Rights Reserved
1 Scope
1.1 Identification
-This software test plan provides detailed tests that are used to
-evaluate the stability and compliance of the Common UNIX Printing
-System ("CUPS") Version 1.1.
+This software test plan provides detailed tests that are used to
+ evaluate the stability and compliance of the Common UNIX Printing
+ System ("CUPS") Version 1.1.
1.2 System Overview
-CUPS provides a portable printing layer for UNIX®-based operating
-systems. It has been developed by Easy
-Software Products to promote a standard printing solution for all
-UNIX vendors and users. CUPS provides the System V and Berkeley
-command-line interfaces.
-CUPS uses the Internet Printing Protocol ("IPP") as the basis for
-managing print jobs and queues. The Line Printer Daemon ("LPD") Server
-Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
-also supported with reduced functionality. CUPS adds network printer
-browsing and PostScript Printer Description ("PPD") based printing
-options to support real-world printing under UNIX.
-CUPS also includes a customized version of GNU Ghostscript
-(currently based off GNU Ghostscript 5.50) and an image file RIP that
-are used to support non-PostScript printers. Sample drivers for HP and
-EPSON printers are included that use these filters.
+CUPS provides a portable printing layer for UNIX®-based operating
+ systems. It has been developed by Easy
+ Software Products to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.
+CUPS uses the Internet Printing Protocol ("IPP") as the basis for
+ managing print jobs and queues. The Line Printer Daemon ("LPD") Server
+ Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description ("PPD") based printing
+ options to support real-world printing under UNIX.
+CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.
1.3 Document Overview
-This software test plan is organized into the following sections:
+This software test plan is organized into the following sections:
- 1 - Scope
- 2 - References
@@ -99,164 +99,164 @@ EPSON printers are included that use these filters.
2 References
2.1 CUPS Documentation
-The following CUPS documentation is referenced by this document:
+The following CUPS documentation is referenced by this document:
-- CUPS-CMP-1.1: CUPS Configuration Management Plan
-- CUPS-IDD-1.1: CUPS System Interface Design Description
-- CUPS-IPP-1.1: CUPS Implementation of IPP
-- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
-- CUPS-SDD-1.1: CUPS Software Design Description
-- CUPS-SPM-1.1.x: CUPS Software Programming Manual
-- CUPS-SSR-1.1: CUPS Software Security Report
-- CUPS-STP-1.1: CUPS Software Test Plan
-- CUPS-SUM-1.1.x: CUPS Software Users Manual
-- CUPS-SVD-1.1: CUPS Software Version Description
+- CUPS-CMP-1.1: CUPS Configuration Management Plan
+- CUPS-IDD-1.1: CUPS System Interface Design Description
+- CUPS-IPP-1.1: CUPS Implementation of IPP
+- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
+- CUPS-SDD-1.1: CUPS Software Design Description
+- CUPS-SPM-1.1.x: CUPS Software Programming Manual
+- CUPS-SSR-1.1: CUPS Software Security Report
+- CUPS-STP-1.1: CUPS Software Test Plan
+- CUPS-SUM-1.1.x: CUPS Software Users Manual
+- CUPS-SVD-1.1: CUPS Software Version Description
2.2 Other Documents
-The following non-CUPS documents are referenced by this document:
+The following non-CUPS documents are referenced by this document:
-
-Adobe PostScript Printer Description File Format Specification,
- Version 4.3.
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.
-
-Adobe PostScript Language Reference, Third Edition.
-- IPP: Job and Printer Set Operations
-- IPP/1.1: Encoding and Transport
-- IPP/1.1: Implementers Guide
-- IPP/1.1: Model and Semantics
-- RFC 1179, Line
-Printer Daemon Protocol
-- RFC 2567, Design
-Goals for an Internet Printing Protocol
-- RFC 2568, Rationale
-for the Structure of the Model and Protocol for the Internet
-Printing Protocol
-- RFC 2569, Mapping
-between LPD and IPP Protocols
-- RFC 2616, Hypertext
-Transfer Protocol -- HTTP/1.1
-- RFC 2617, HTTP
-Authentication: Basic and Digest Access Authentication
+Adobe PostScript Language Reference, Third Edition.
+- IPP: Job and Printer Set Operations
+- IPP/1.1: Encoding and Transport
+- IPP/1.1: Implementers Guide
+- IPP/1.1: Model and Semantics
+- RFC 1179, Line Printer
+ Daemon Protocol
+- RFC 2567, Design Goals
+ for an Internet Printing Protocol
+- RFC 2568, Rationale
+ for the Structure of the Model and Protocol for the Internet
+ Printing Protocol
+- RFC 2569, Mapping
+ between LPD and IPP Protocols
+- RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1
+- RFC 2617, HTTP
+ Authentication: Basic and Digest Access Authentication
3 Test Procedure
-The test software and data files are located in the test
- subdirectory of the source distribution. A script is provided to
-compile the ipptest
program and run all of the tests that
-follow, producing a success/fail report.
-The test
target of the top-level makefile can be used
-to run this script:
+The test software and data files are located in the test
+ subdirectory of the source distribution. A script is provided to
+ compile the ipptest
program and run all of the tests that
+ follow, producing a success/fail report.
+The test
target of the top-level makefile can be used to
+ run this script:
make test
-or you can run the test script directly:
+or you can run the test script directly:
cd test
./run-stp-tests
-A Software Test Report is stored in HTML and PDF files that are
-generated using the HTMLDOC
- software.
+A Software Test Report is stored in HTML and PDF files that are
+ generated using the HTMLDOC
+ software.
4 IPP Compliance Tests
-This section describes the tests used to validate the IPP standards
-compliance of the CUPS server.
+This section describes the tests used to validate the IPP standards
+ compliance of the CUPS server.
4.1 Request Tests
-These tests verify that the CUPS scheduler only accepts valid IPP
-requests that start with the attributes-charset
and
+These tests verify that the CUPS scheduler only accepts valid IPP
+ requests that start with the attributes-charset
and
attributes-natural-language
attributes and also contain a
-printer-uri
or job-uri
attribute.
+printer-uri
or job-uri
attribute.
It also verifies that the CUPS scheduler always responds with
attributes-charset
and attributes-natural-language
- attributes, using default values if they are not provided by the
-client.
+ attributes, using default values if they are not provided by the
+ client.
4.2 CUPS Printer Operation Tests
-These tests verify that the CUPS printer operations are supported
-and function properly. Two printers called Test1
and
-Test2
are created, one as a PostScript printer and one as a
-raster printer.
+These tests verify that the CUPS printer operations are supported and
+ function properly. Two printers called Test1
and
+Test2
are created, one as a PostScript printer and one as a
+ raster printer.
4.3 Job Operation Tests
-These test verify that the CUPS scheduler accepts print jobs for all
-supported file formats and that the cancel-job
,
-hold-job
, and resume-job
operations work.
+These test verify that the CUPS scheduler accepts print jobs for all
+ supported file formats and that the cancel-job
,
+hold-job
, and resume-job
operations work.
5 Command Tests
-This section describes the tests used to validate the Berkeley and
-System V commands included with CUPS.
+This section describes the tests used to validate the Berkeley and
+ System V commands included with CUPS.
5.1 lpadmin
-This test verifies that printers can be added, modified, and
-defaulted using the lpadmin
command.
+This test verifies that printers can be added, modified, and
+ defaulted using the lpadmin
command.
5.2 lpc
-This test verifies that the lpc
command can show the
-current status of all print queues.
+This test verifies that the lpc
command can show the
+ current status of all print queues.
5.3 lpq
-This test verifies that the lpq
command lists any jobs
-in the queue.
+This test verifies that the lpq
command lists any jobs
+ in the queue.
5.4 lpstat
-This test verifies that the lpstat
command works with
-all reports using the "-t
" option.
+This test verifies that the lpstat
command works with
+ all reports using the "-t
" option.
5.5 lp
-This test verifies that the lp
command works with both
-the default destination and a specific destination.
+This test verifies that the lp
command works with both
+ the default destination and a specific destination.
5.6 lpr
-This test verifies that the lpr
command works with both
-the default destination and a specific destination.
+This test verifies that the lpr
command works with both
+ the default destination and a specific destination.
5.7 lprm
-This test verifies that the lprm
command can properly
-cancel a job.
+This test verifies that the lprm
command can properly
+ cancel a job.
5.8 cancel
-This test verifies that the cancel
command can properly
-cancel a job or all jobs.
+This test verifies that the cancel
command can properly
+ cancel a job or all jobs.
5.9 lpinfo
-This test verifies that the lpinfo
command returns a
-list of available printer drivers and devices.
+This test verifies that the lpinfo
command returns a
+ list of available printer drivers and devices.
A Glossary
A.1 Terms
-- C
-- A computer language.
-- parallel
-- Sending or receiving data more than 1 bit at a time.
-- pipe
-- A one-way communications channel between two programs.
-- serial
-- Sending or receiving data 1 bit at a time.
-- socket
-- A two-way network communications channel.
+- C
+- A computer language.
+- parallel
+- Sending or receiving data more than 1 bit at a time.
+- pipe
+- A one-way communications channel between two programs.
+- serial
+- Sending or receiving data 1 bit at a time.
+- socket
+- A two-way network communications channel.
A.2 Acronyms
-- ASCII
-- American Standard Code for Information Interchange
-- CUPS
-- Common UNIX Printing System
-- ESC/P
-- EPSON Standard Code for Printers
-- FTP
-- File Transfer Protocol
-- HP-GL
-- Hewlett-Packard Graphics Language
-- HP-PCL
-- Hewlett-Packard Page Control Language
-- HP-PJL
-- Hewlett-Packard Printer Job Language
-- IETF
-- Internet Engineering Task Force
-- IPP
-- Internet Printing Protocol
-- ISO
-- International Standards Organization
-- LPD
-- Line Printer Daemon
-- MIME
-- Multimedia Internet Mail Exchange
-- PPD
-- PostScript Printer Description
-- SMB
-- Server Message Block
-- TFTP
-- Trivial File Transfer Protocol
+- ASCII
+- American Standard Code for Information Interchange
+- CUPS
+- Common UNIX Printing System
+- ESC/P
+- EPSON Standard Code for Printers
+- FTP
+- File Transfer Protocol
+- HP-GL
+- Hewlett-Packard Graphics Language
+- HP-PCL
+- Hewlett-Packard Page Control Language
+- HP-PJL
+- Hewlett-Packard Printer Job Language
+- IETF
+- Internet Engineering Task Force
+- IPP
+- Internet Printing Protocol
+- ISO
+- International Standards Organization
+- LPD
+- Line Printer Daemon
+- MIME
+- Multimedia Internet Mail Exchange
+- PPD
+- PostScript Printer Description
+- SMB
+- Server Message Block
+- TFTP
+- Trivial File Transfer Protocol
diff --git a/doc/stp.pdf b/doc/stp.pdf
index 0063718909..2251be5b78 100644
Binary files a/doc/stp.pdf and b/doc/stp.pdf differ
diff --git a/doc/sum.html b/doc/sum.html
index 576c6c8b05..8f84e624e4 100644
--- a/doc/sum.html
+++ b/doc/sum.html
@@ -124,24 +124,26 @@ Copyright 1997-2001, All Rights Reserved
Preface
-This software users manual describes how to use the Common UNIX
-Printing SystemTM ("CUPSTM") Version 1.1.7.
+This software users manual describes how to use the Common UNIX
+ Printing <<<<<<< sum.shtml SystemTM ("CUPSTM")
+ Version 1.1.7. ======= SystemTM ("CUPSTM")
+ Version 1.1.13. >>>>>>> 1.29
System Overview
-CUPS provides a portable printing layer for UNIX®-based operating
-systems. It has been developed by Easy
-Software Products to promote a standard printing solution for all
-UNIX vendors and users. CUPS provides the System V and Berkeley
-command-line interfaces.
-CUPS uses the Internet Printing Protocol ("IPP") as the basis for
-managing print jobs and queues. The Line Printer Daemon ("LPD") Server
-Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
-also supported with reduced functionality. CUPS adds network printer
-browsing and PostScript Printer Description ("PPD") based printing
-options to support real-world printing under UNIX.
-CUPS also includes a customized version of GNU Ghostscript
-(currently based off GNU Ghostscript 5.50) and an image file RIP that
-are used to support non-PostScript printers. Sample drivers for HP and
-EPSON printers are included that use these filters.
+CUPS provides a portable printing layer for UNIX®-based operating
+ systems. It has been developed by Easy
+ Software Products to promote a standard printing solution for all
+ UNIX vendors and users. CUPS provides the System V and Berkeley
+ command-line interfaces.
+CUPS uses the Internet Printing Protocol ("IPP") as the basis for
+ managing print jobs and queues. The Line Printer Daemon ("LPD") Server
+ Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are
+ also supported with reduced functionality. CUPS adds network printer
+ browsing and PostScript Printer Description ("PPD") based printing
+ options to support real-world printing under UNIX.
+CUPS also includes a customized version of GNU Ghostscript (currently
+ based off GNU Ghostscript 5.50) and an image file RIP that are used to
+ support non-PostScript printers. Sample drivers for HP and EPSON
+ printers are included that use these filters.
Document Overview
@@ -155,16 +157,16 @@ EPSON printers are included that use these filters.
A - Software License Agreement
Notation Conventions
-Various font and syntax conventions are used in this guide. Examples
-and their meanings and uses are explained below:
+
Various font and syntax conventions are used in this guide. Examples
+ and their meanings and uses are explained below:
Example Description
lpstat
-
lpstat(1)
The names of commands;
-the first mention of a command or function in a chapter is followed by
-a manual page section number.
+
lpstat(1)
The names of commands;
+ the first mention of a command or function in a chapter is followed by
+ a manual page section number.
/var
/usr/share/cups/data/testprint.ps
@@ -174,217 +176,217 @@ File and directory names.
Screen output.
lp -d printer filename ENTER
- Literal user input; special keys like ENTER are
+ Literal user input; special keys like ENTER are
in ALL CAPS.
-12.3 Numbers in the text are
-written using the period (.) to indicate the decimal point.
+12.3 Numbers in the text are
+ written using the period (.) to indicate the decimal point.
Abbreviations
- The following abbreviations are used throughout this manual:
+ The following abbreviations are used throughout this manual:
-- kb
+- kb
- Kilobytes, or 1024 bytes
-
-- Mb
+
+- Mb
- Megabytes, or 1048576 bytes
-
-- Gb
+
+- Gb
- Gigabytes, or 1073741824 bytes
-
+
Other References
-- CUPS Software Administrators Manual
+- CUPS Software Administrators Manual
- An administration guide for the CUPS software.
-
-- CUPS Software Programmers Manual
-- A programmer guide for interfacing with and/or extending the CUPS
+
+- CUPS Software Programmers Manual
+- A programmer guide for interfacing with and/or extending the CUPS
software.
-
+
1 - Printing System Overview
-This chapter provides an overview of how the Common UNIX Printing
-System works.
+This chapter provides an overview of how the Common UNIX Printing
+ System works.
The Printing Problem
-For years the printing problem has plagued UNIX. Unlike
-Microsoft® Windows® or Mac OS, UNIX has no standard interface or system
-in place for supporting printers. Among the solutions currently
-available, the Berkeley and System V printing systems are the most
-prevalent.
-These printing systems support line printers (text only) or
-PostScript printers (text and graphics), and with some coaxing they can
-be made to support a full range of printers and file formats. However,
-because each varient of the UNIX operating system uses a different
-printing system than the next developing printer drivers for a wide
-range of printers and operating systems is extremely difficult. That
-combined with the limited volume of customers for each UNIX varient has
-forced most printer vendors to give up supporting UNIX entirely.
-CUPS is designed to eliminate the printing problem. One
-common printing system can be used by all UNIX varients to support the
-printing needs of users. Printer vendors can use its modular filter
-interface to develop a single driver program that supports a wide range
-of file formats with little or no effort. Since CUPS provides both the
-System V and Berkeley printing commands, users (and applications) can
-reap the benefits of this new technology with no changes.
+For years the printing problem has plagued UNIX. Unlike
+ Microsoft® Windows® or Mac OS, UNIX has no standard interface or system
+ in place for supporting printers. Among the solutions currently
+ available, the Berkeley and System V printing systems are the most
+ prevalent.
+These printing systems support line printers (text only) or
+ PostScript printers (text and graphics), and with some coaxing they can
+ be made to support a full range of printers and file formats. However,
+ because each varient of the UNIX operating system uses a different
+ printing system than the next developing printer drivers for a wide
+ range of printers and operating systems is extremely difficult. That
+ combined with the limited volume of customers for each UNIX varient has
+ forced most printer vendors to give up supporting UNIX entirely.
+CUPS is designed to eliminate the printing problem. One common
+ printing system can be used by all UNIX varients to support the
+ printing needs of users. Printer vendors can use its modular filter
+ interface to develop a single driver program that supports a wide range
+ of file formats with little or no effort. Since CUPS provides both the
+ System V and Berkeley printing commands, users (and applications) can
+ reap the benefits of this new technology with no changes.
The Technology
-CUPS is based upon an emerging Internet standard called the Internet
-Printing Protocol. IPP has been embraced by dozens of printer and
-printer server manufacturers and is supported by Microsoft Windows
-2000.
-IPP defines a standard protocol for printing as well as managing
-print jobs and printer options like media size, resolution, and so
-forth. Like all IP-based protocols, IPP can be used locally or over the
-Internet to printers hundreds or thousands of miles away. Unlike other
-protocols, however, IPP also supports access control, authentication,
-and encryption, making it a much more capable and secure printing
-solution than older ones.
-IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP")
-which is the basis of web servers on the Internet. This allows users to
-view documentation, check status information on a printer or server,
-and manage their printers, classes, and jobs using their web browser.
-CUPS provides a complete IPP/1.1 based printing system that provides
-Basic, Digest, and local certificate authentication and user, domain,
-or IP-based access control. TLS encryption will be available in future
-versions of CUPS.
+CUPS is based upon an emerging Internet standard called the Internet
+ Printing Protocol. IPP has been embraced by dozens of printer and
+ printer server manufacturers and is supported by Microsoft Windows
+ 2000.
+IPP defines a standard protocol for printing as well as managing
+ print jobs and printer options like media size, resolution, and so
+ forth. Like all IP-based protocols, IPP can be used locally or over the
+ Internet to printers hundreds or thousands of miles away. Unlike other
+ protocols, however, IPP also supports access control, authentication,
+ and encryption, making it a much more capable and secure printing
+ solution than older ones.
+IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP")
+ which is the basis of web servers on the Internet. This allows users to
+ view documentation, check status information on a printer or server,
+ and manage their printers, classes, and jobs using their web browser.
+CUPS provides a complete IPP/1.1 based printing system that provides
+ Basic, Digest, and local certificate authentication and user, domain,
+ or IP-based access control. TLS encryption will be available in future
+ versions of CUPS.
Jobs
-Each file or set of files that is submitted for printing is called a
-job. Jobs are identified by a unique number starting at 1 and are
-assigned to a particular destination, usually a printer. Jobs can also
-have options associated with them such as media size, number of copies,
-and priority.
+Each file or set of files that is submitted for printing is called a
+ job. Jobs are identified by a unique number starting at 1 and are
+ assigned to a particular destination, usually a printer. Jobs can also
+ have options associated with them such as media size, number of copies,
+ and priority.
Classes
-CUPS supports collections of printers known as classes. Jobs
-sent to a class are forwarded to the first available printer in the
-class.
+CUPS supports collections of printers known as classes. Jobs
+ sent to a class are forwarded to the first available printer in the
+ class.
Filters
-Filters allow a user or application to print many types of files
-without extra effort. Print jobs sent to a CUPS server are filtered
-before sending them to a printer. Some filters convert job files to
-different formats that the printer can understand. Others perform page
-selection and ordering tasks.
-CUPS provides filters for printing many types of image files,
-HP-GL/2 files, PDF files, and text files. CUPS also supplies PostScript
-and image file Raster Image Processor ("RIP") filters that convert
-PostScript or image files into bitmaps that can be sent to a raster
-printer.
+Filters allow a user or application to print many types of files
+ without extra effort. Print jobs sent to a CUPS server are filtered
+ before sending them to a printer. Some filters convert job files to
+ different formats that the printer can understand. Others perform page
+ selection and ordering tasks.
+CUPS provides filters for printing many types of image files, HP-GL/2
+ files, PDF files, and text files. CUPS also supplies PostScript and
+ image file Raster Image Processor ("RIP") filters that convert
+ PostScript or image files into bitmaps that can be sent to a raster
+ printer.
Backends
-Backends perform the most important task of all - they send the
-filtered print data to the printer.
-CUPS provides backends for printing over parallel, serial, and USB
-ports, and over the network via the IPP, JetDirect (AppSocket), and
-Line Printer Daemon ("LPD") protocols. Additional backends are
-available in network service packages such as the SMB backend included
-with the popular SAMBA software.
-Backends are also used to determine the available devices. On
-startup each backend is asked for a list of devices it supports, and
-any information that is available. This allows the parallel backend to
-tell CUPS that an EPSON Stylus Color 600 printer is attached to
-parallel port 1, for example.
+Backends perform the most important task of all - they send the
+ filtered print data to the printer.
+CUPS provides backends for printing over parallel, serial, and USB
+ ports, and over the network via the IPP, JetDirect (AppSocket), and
+ Line Printer Daemon ("LPD") protocols. Additional backends are
+ available in network service packages such as the SMB backend included
+ with the popular SAMBA software.
+Backends are also used to determine the available devices. On startup
+ each backend is asked for a list of devices it supports, and any
+ information that is available. This allows the parallel backend to tell
+ CUPS that an EPSON Stylus Color 600 printer is attached to parallel
+ port 1, for example.
Printer Drivers
-Printer drivers in CUPS consist of one of more filters specific to a
-printer. CUPS includes sample printer drivers for Hewlett-Packard
-LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color,
-and Stylus Photo printers. While these drivers do not generate optimal
-output for the different printer models, they do provide basic printing
-and demonstrate how you can write your own printer drivers and
-incorporate them into CUPS.
+Printer drivers in CUPS consist of one of more filters specific to a
+ printer. CUPS includes sample printer drivers for Hewlett-Packard
+ LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color,
+ and Stylus Photo printers. While these drivers do not generate optimal
+ output for the different printer models, they do provide basic printing
+ and demonstrate how you can write your own printer drivers and
+ incorporate them into CUPS.
Networking
-Printers and classes on the local system are automatically shared
-with other systems on the network. This allows you to setup one system
-to print to a printer and use this system as a printer server or spool
-host for all of the others. Users may then select a local printer by
-name or a remote printer using "name@server".
-CUPS also provides implicit classes, which are collections of
-printers and/or classes with the same name. This allows you to setup
-multiple servers pointing to the same physical network printer, for
-example, so that you aren't relying on a single system for printing.
-Because this also works with printer classes, you can setup multiple
-servers and printers and never worry about a single point of failure
-unless all of the printers and servers go down!
+Printers and classes on the local system are automatically shared
+ with other systems on the network. This allows you to setup one system
+ to print to a printer and use this system as a printer server or spool
+ host for all of the others. Users may then select a local printer by
+ name or a remote printer using "name@server".
+CUPS also provides implicit classes, which are collections of
+ printers and/or classes with the same name. This allows you to setup
+ multiple servers pointing to the same physical network printer, for
+ example, so that you aren't relying on a single system for printing.
+ Because this also works with printer classes, you can setup multiple
+ servers and printers and never worry about a single point of failure
+ unless all of the printers and servers go down!
2 - Using the Printing System
-This chapter shows you how to submit, query, and cancel print jobs
-to different printers.
+This chapter shows you how to submit, query, and cancel print jobs to
+ different printers.
Submitting Files for Printing
CUPS provides both the System V (lp(1)
) and Berkeley (
-lpr(1)
) printing commands. Type the following command to print a
-file to the default (or only) printer on the system:
+lpr(1)) printing commands. Type the following command to print a
+ file to the default (or only) printer on the system:
lp filename ENTER
-or:
+or:
lpr filename ENTER
-CUPS understands many different types of files directly, including
-PostScript and image files. This allows you to print from inside your
-applications or at the command-line, whichever is most convenient!
+CUPS understands many different types of files directly, including
+ PostScript and image files. This allows you to print from inside your
+ applications or at the command-line, whichever is most convenient!
Choosing a Printer
-Many systems will have more than one printer available to the user.
-These printers can be attached to the local system via a parallel,
-serial, or USB port, or available over the network.
-Use the lpstat(1)
command to see a list of available
-printers:
+Many systems will have more than one printer available to the user.
+ These printers can be attached to the local system via a parallel,
+ serial, or USB port, or available over the network.
+Use the lpstat(1)
command to see a list of available
+ printers:
lpstat -p -d ENTER
-The -p
option specifies that you want to see a list of
-printers, and the -d
option reports the current system
-default printer or class.
-Use the -d
option with the lp
command to
-print to a specific printer:
+The -p
option specifies that you want to see a list of
+ printers, and the -d
option reports the current system
+ default printer or class.
+Use the -d
option with the lp
command to
+ print to a specific printer:
lp -d printer filename ENTER
-or the -P
option with the lpr
command:
+or the -P
option with the lpr
command:
lpr -P printer filename ENTER
Setting Printer Options
-For many types of files, the default printer options may be
-sufficient for your needs. However, there may be times when you need to
-change the options for a particular file you are printing.
-The lp
and lpr
commands allow you to pass
-printer options using the -o
option:
+For many types of files, the default printer options may be
+ sufficient for your needs. However, there may be times when you need to
+ change the options for a particular file you are printing.
+The lp
and lpr
commands allow you to pass
+ printer options using the -o
option:
lp -o landscape -o scaling=75 -o media=A4 filename.jpg
lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
-The available printer options vary depending on the printer. The
-standard options are described in Chapter
-3, "Standard Printing Options".
+The available printer options vary depending on the printer. The
+ standard options are described in Chapter
+ 3, "Standard Printing Options".
Printing Multiple Copies
-Both the lp
and lpr
commands have options
-for printing more than one copy of a file:
+Both the lp
and lpr
commands have options
+ for printing more than one copy of a file:
lp -n num-copies filename ENTER
lpr -#num-copies filename ENTER
-Copies are normally not collated for you. Use the -o
-Collate=True
option to get collated copies :
+Copies are normally not collated for you. Use the -o
+ Collate=True
option to get collated copies :
lp -n num-copies -o Collate=True filename ENTER
@@ -394,8 +396,8 @@ Collate=True option to get collated copies :
Checking the Printer Status from the Command-Line
-The lpstat
command can be used to check for jobs that
-you have submitted for printing:
+The lpstat
command can be used to check for jobs that
+ you have submitted for printing:
lpstat ENTER
@@ -405,7 +407,7 @@ Printer-3 johndoe 372842
The jobs are listed in the order they will be printed. Use the
--p
option to see which files and printers are active:
+-p option to see which files and printers are active:
lpstat -p ENTER
@@ -414,8 +416,8 @@ printer DeskJet now printing DeskJet-1.
-Use the -o
and -p
options together to show
-the jobs and the printers:
+Use the -o
and -p
options together to show
+ the jobs and the printers:
lpstat -o -p ENTER
@@ -426,37 +428,37 @@ printer DeskJet now printing DeskJet-1.
Checking the Printer Status from the Web
-Since CUPS uses the Internet Printing Protocol, it is also a
-fully-functional web server. To use your web browser to monitor the
-printers on your system, open the URL:
+Since CUPS uses the Internet Printing Protocol, it is also a
+ fully-functional web server. To use your web browser to monitor the
+ printers on your system, open the URL:
http://localhost:631
-From there you can view the status of classes, jobs, and printers
-with the click of a button!
+From there you can view the status of classes, jobs, and printers
+ with the click of a button!
Canceling a Print Job
-The cancel(1)
and lprm(1)
commands cancel
-a print job:
+The cancel(1)
and lprm(1)
commands cancel a
+ print job:
cancel job-id ENTER
lprm job-id ENTER
-The job-id
is the number that was reported to you by
-the lp
or lpstat
commands.
-3 - Standard Printer
-Options
-This chapter describes the standard printer options that are
-available when printing with the lp
and lpr
- commands.
+The job-id
is the number that was reported to you by the
+ lp
or lpstat
commands.
+3 - Standard Printer
+ Options
+This chapter describes the standard printer options that are
+ available when printing with the lp
and lpr
+ commands.
General Options
-The following options apply when printing all types of files.
+The following options apply when printing all types of files.
Setting the Orientation
-The -o landscape
option will rotate the page 90 degrees
-to print in landscape orientation:
+The -o landscape
option will rotate the page 90 degrees
+ to print in landscape orientation:
lp -o landscape filename ENTER
@@ -466,8 +468,8 @@ to print in landscape orientation:
Selecting the Media Size, Type, and Source
-The -o media=xyz
option sets the media size, type,
-and/or source:
+The -o media=xyz
option sets the media size, type,
+ and/or source:
lp -o media=Letter filename ENTER
@@ -478,31 +480,31 @@ and/or source:
-The available media sizes, types, and sources depend on the printer,
-but most support the following options (case is not significant):
-
-Letter
- US Letter (8.5x11 inches, or 216x279mm)
-Legal
- US Legal (8.5x14 inches, or 216x356mm)
-A4
- ISO A4 (8.27x11.69 inches, or 210x297mm)
-COM10
- US #10 Envelope (9.5x4.125 inches, or
- 241x105mm)
-DL
- ISO DL Envelope (8.66x4.33 inches, or 220x110mm)
-Transparency
- Transparency media type or source
-Upper
- Upper paper tray
-Lower
- Lower paper tray
-MultiPurpose
- Multi-purpose paper tray
-LargeCapacity
- Large capacity paper tray
-
-The actual options supported are defined in the printer's PPD file
-in the PageSize
, InputSlot
, and
-MediaType
options.
+The available media sizes, types, and sources depend on the printer,
+ but most support the following options (case is not significant):
+
+Letter
- US Letter (8.5x11 inches, or 216x279mm)
+Legal
- US Legal (8.5x14 inches, or 216x356mm)
+A4
- ISO A4 (8.27x11.69 inches, or 210x297mm)
+COM10
- US #10 Envelope (9.5x4.125 inches, or
+ 241x105mm)
+DL
- ISO DL Envelope (8.66x4.33 inches, or 220x110mm)
+Transparency
- Transparency media type or source
+Upper
- Upper paper tray
+Lower
- Lower paper tray
+MultiPurpose
- Multi-purpose paper tray
+LargeCapacity
- Large capacity paper tray
+
+The actual options supported are defined in the printer's PPD file in
+ the PageSize
, InputSlot
, and MediaType
+ options.
Printing On Both Sides of the Paper
-The -o sides=two-sided-short-edge
and -o
-sides=two-sided-long-edge
options will enable duplexing on the
-printer, if the printer supports it. The -o
-sides=two-sided-short-edge
option is suitable for landscape
-pages, while the -o sides=two-sided-long-edge
option is
-suitable for portrait pages:
+The -o sides=two-sided-short-edge
and -o
+ sides=two-sided-long-edge
options will enable duplexing on the
+ printer, if the printer supports it. The -o
+ sides=two-sided-short-edge
option is suitable for landscape
+ pages, while the -o sides=two-sided-long-edge
option is
+ suitable for portrait pages:
lp -o sides=two-sided-short-edge filename ENTER
@@ -510,7 +512,7 @@ suitable for portrait pages:
lpr -o sides=two-sided-long-edge filename ENTER
-The default is to print single-sided:
+The default is to print single-sided:
lp -o sides=one-sided filename ENTER
@@ -518,10 +520,10 @@ suitable for portrait pages:
Banner Options
-The following options apply when printing all types of files.
+The following options apply when printing all types of files.
Selecting the Banner Page(s)
-The -o jobsheets=start,end
option sets the banner
-page(s) to use for a job:
+The -o jobsheets=start,end
option sets the banner
+ page(s) to use for a job:
lp -o job-sheets=none filename ENTER
@@ -529,31 +531,31 @@ page(s) to use for a job:
lpr -o job-sheets=classified,classified filename ENTER
-If only one banner file is specified, it will be printed before the
-files in the job. If a second banner file is specified, it is printed
-after the files in the job.
-The available banner pages depend on the local system configuration;
-CUPS includes the following banner files:
-
-none
- Do not produce a banner page.
-classified
- A banner page with a "classified" label
-at the top and bottom.
-confidential
- A banner page with a "confidential"
-label at the top and bottom.
-secret
- A banner page with a "secret" label at the
-top and bottom.
-standard
- A banner page with no label at the top and
-bottom.
-topsecret
- A banner page with a "top secret" label
-at the top and bottom.
-unclassified
- A banner page with an "unclassified"
-label at the top and bottom.
+If only one banner file is specified, it will be printed before the
+ files in the job. If a second banner file is specified, it is printed
+ after the files in the job.
+The available banner pages depend on the local system configuration;
+ CUPS includes the following banner files:
+
+none
- Do not produce a banner page.
+classified
- A banner page with a "classified" label at
+ the top and bottom.
+confidential
- A banner page with a "confidential"
+ label at the top and bottom.
+secret
- A banner page with a "secret" label at the top
+ and bottom.
+standard
- A banner page with no label at the top and
+ bottom.
+topsecret
- A banner page with a "top secret" label at
+ the top and bottom.
+unclassified
- A banner page with an "unclassified"
+ label at the top and bottom.
Document Options
-The following options apply when printing all types of files.
+The following options apply when printing all types of files.
Selecting a Range of Pages
-The -o page-ranges=pages
option selects a range of
-pages for printing:
+The -o page-ranges=pages
option selects a range of pages
+ for printing:
lp -o page-ranges=1 filename ENTER
@@ -562,14 +564,14 @@ pages for printing:
lpr -o page-ranges=1-4,7,9-12 filename ENTER
-As shown above, the pages
value can be a single page, a
-range of pages, or a collection of page numbers and ranges separated by
-commas. The pages will always be printed in ascending order, regardless
-of the order of the pages in the page-ranges
option.
-The default is to print all pages.
+As shown above, the pages
value can be a single page, a
+ range of pages, or a collection of page numbers and ranges separated by
+ commas. The pages will always be printed in ascending order, regardless
+ of the order of the pages in the page-ranges
option.
+The default is to print all pages.
Selecting Even or Odd Pages
-Use the -o page-set=set
option to select the even or
-odd pages:
+Use the -o page-set=set
option to select the even or odd
+ pages:
lp -o page-set=odd filename ENTER
@@ -577,11 +579,11 @@ odd pages:
lpr -o page-set=even filename ENTER
-The default is to print all pages.
+The default is to print all pages.
N-Up Printing
-The -o number-up=value
option selects N-Up printing.
- N-Up printing places multiple document pages on a single printed page.
- CUPS supports 1-Up, 2-Up, and 4-Up formats:
+The -o number-up=value
option selects N-Up printing.
+ N-Up printing places multiple document pages on a single printed page.
+ CUPS supports 1-Up, 2-Up, and 4-Up formats:
lp -o number-up=1 filename ENTER
@@ -590,34 +592,34 @@ odd pages:
lpr -o number-up=4 filename ENTER
-The default format is 1-Up.
+The default format is 1-Up.
Setting the Brightness
-You can control the overall brightness of the printed output using
-the -o brightness=percent
option:
+You can control the overall brightness of the printed output using
+ the -o brightness=percent
option:
lp -o brightness=120 filename ENTER
lpr -o brightness=120 filename ENTER
-Values greater than 100 will lighten the print, while values less
-than 100 will darken it.
+Values greater than 100 will lighten the print, while values less
+ than 100 will darken it.
Setting the Gamma Correction
-You can control the overall gamma correction of the printed output
-using the -o gamma=value
option:
+You can control the overall gamma correction of the printed output
+ using the -o gamma=value
option:
lp -o gamma=1700 filename ENTER
lpr -o gamma=1700 filename ENTER
-Values greater than 1000 will lighten the print, while values less
-than 1000 will darken it. The default gamma is 1000.
+Values greater than 1000 will lighten the print, while values less
+ than 1000 will darken it. The default gamma is 1000.
Text Options
-The following options apply when printing text files.
+The following options apply when printing text files.
Setting the Number of Characters Per Inch
-The -o cpi=value
option sets the number of characters
-per inch:
+The -o cpi=value
option sets the number of characters
+ per inch:
lp -o cpi=10 filename ENTER
@@ -625,32 +627,32 @@ per inch:
lpr -o cpi=17 filename ENTER
-The default characters per inch is 10.
+The default characters per inch is 10.
Setting the Number of Lines Per Inch
-The -o lpi=value
option sets the number of lines per
-inch:
+The -o lpi=value
option sets the number of lines per
+ inch:
lp -o lpi=6 filename ENTER
lpr -o lpi=8 filename ENTER
-The default lines per inch is 6.
+The default lines per inch is 6.
Setting the Number of Columns
-The -o columns=value
option sets the number of text
-columns:
+The -o columns=value
option sets the number of text
+ columns:
lp -o columns=2 filename ENTER
lpr -o columns=3 filename ENTER
-The default number of columns is 1.
+The default number of columns is 1.
Setting the Page Margins
-Normally the page margins are set to the hard limits of the printer.
-Use the -o page-left=value
, -o page-right=value
+
Normally the page margins are set to the hard limits of the printer.
+ Use the -o page-left=value
, -o page-right=value
, -o page-top=value
, and -o page-bottom=value
- options to adjust the page margins:
+ options to adjust the page margins:
lp -o page-left=value filename ENTER
@@ -660,13 +662,13 @@ Use the -o page-left=value
, -o page-right=value
lpr -o page-bottom=value filename ENTER
-The value
argument is the margin in points; each point
-is 1/72 inch or 0.35mm.
+The value
argument is the margin in points; each point
+ is 1/72 inch or 0.35mm.
Pretty Printing
-The -o prettyprint
option puts a header at the top of
-each page with the page number, job title (usually the filename), and
-the date. Also, C and C++ keywords are highlighted, and comment lines
-are italicized:
+The -o prettyprint
option puts a header at the top of
+ each page with the page number, job title (usually the filename), and
+ the date. Also, C and C++ keywords are highlighted, and comment lines
+ are italicized:
lp -o prettyprint filename ENTER
@@ -674,49 +676,57 @@ are italicized:
Image Options
-The following options apply when printing image files.
+The following options apply when printing image files.
Positioning the Image
-The -o position=name
option specifies the position of
-the image on the page:
-
-center
- Center the image on the page (default)
-top
- Print the image centered at the top of the page
-left
- Print the image centered on the left of page
-right
- Print the image centered on the right of the
-page
-top-left
- Print the image at the top left corner of
- the page
-top-right
- Print the image at the top right corner of
- the page
-bottom
- Print the image centered at the bottom of
- the page
-bottom-left
- Print the image at the bottom left
- corner of the page
-bottom-right
- Print the image at the bottom right
- corner of the page
+The -o position=name
option specifies the position of
+ the image on the page:
+
+center
- Center the image on the page (default)
+top
- Print the image centered at the top of the page
+left
- Print the image centered on the left of page
+right
- Print the image centered on the right of the
+ page
+top-left
- Print the image at the top left corner of
+ the page
+top-right
- Print the image at the top right corner of
+ the page
+bottom
- Print the image centered at the bottom of the
+ page
+bottom-left
- Print the image at the bottom left corner
+ of the page
+bottom-right
- Print the image at the bottom right
+ corner of the page
Scaling the Image
-The -o scaling=percent
and -o ppi=value
- options change the size of a printed image:
+The -o scaling=percent
, -o ppi=value
, and
+-o natural-scaling=percent
options change the size of a printed
+ image:
lp -o scaling=percent filename ENTER
lp -o ppi=value filename ENTER
-lpr -o ppi=value filename ENTER
+lpr -o natural-scaling=percent filename ENTER
-The percent
value is a number from 1 to 800 specifying
-the size in relation to the page (not the image.) A scaling of
-100 percent will fill the page as completely as the image aspect ratio
-allows. A scaling of 200 percent will print on up to 4 pages.
-The ppi value
is a number from 1 to 1200 specifying the
-resolution of the image in pixels per inch. An image that is 3000x2400
-pixels will print 10x8 inches at 300 pixels per inch, for example. If
-the specified resolution makes the image larger than the page, multiple
-pages will be printed to satisfy the request.
+The scaling=percent
value is a number from 1 to 800
+ specifying the size in relation to the page (not the image.) A
+ scaling of 100 percent will fill the page as completely as the image
+ aspect ratio allows. A scaling of 200 percent will print on up to 4
+ pages.
+The ppi=value
value is a number from 1 to 1200
+ specifying the resolution of the image in pixels per inch. An image
+ that is 3000x2400 pixels will print 10x8 inches at 300 pixels per inch,
+ for example. If the specified resolution makes the image larger than
+ the page, multiple pages will be printed to satisfy the request.
+The natural-scaling=percent
value is a number from 1 to
+ 800 specifying the size in relation to the natural image size. A
+ scaling of 100 percent will print the image at its natural size, while
+ a scaling of 50 percent will print the image at half its natural size.
+ If the specified scaling makes the image larger than the page, multiple
+ pages will be printed to satisfy the request.
Adjusting the Hue (Tint) of an Image
-The -o hue=value
option will adjust the hue of the
-printed image, much like the tint control on your television:
+The -o hue=value
option will adjust the hue of the
+ printed image, much like the tint control on your television:
lp -o hue=value filename ENTER
@@ -725,9 +735,9 @@ printed image, much like the tint control on your television:
-The value
argument is a number from -360 to 360 and
-represents the color hue rotation. The following table summarizes the
-change you'll see with different colors:
+
The value
argument is a number from -360 to 360 and
+ represents the color hue rotation. The following table summarizes the
+ change you'll see with different colors:
Original hue=-45 hue=45
@@ -740,84 +750,83 @@ change you'll see with different colors:
-The default hue adjustment is 0.
+The default hue adjustment is 0.
Adjusting the Saturation (Color) of an Image
-The -o saturation=percent
option adjusts the saturation
-of the colors in an image, much like the color knob on your television:
+The -o saturation=percent
option adjusts the saturation
+ of the colors in an image, much like the color knob on your television:
lp -o saturation=percent filename ENTER
lpr -o saturation=percent filename ENTER
-The percent
argument specifies the color saturation
-from 0 to 200. A color saturation of 0 produces a black-and-white
-print, while a value of 200 will make the colors extremely intense.
-The default saturation is 100.
+
The percent
argument specifies the color saturation from
+ 0 to 200. A color saturation of 0 produces a black-and-white print,
+ while a value of 200 will make the colors extremely intense.
+The default saturation is 100.
HP-GL/2 Options
-The following options apply to HP-GL/2 files.
+The following options apply to HP-GL/2 files.
Printing in Black
-The -o blackplot
option specifies that all pens should
-plot in black:
+The -o blackplot
option specifies that all pens should
+ plot in black:
lp -o blackplot filename ENTER
lpr -o blackplot filename ENTER
-The default is to use the colors defined in the plot file or the
-standard pen colors defined in the HP-GL/2 reference manual from
-Hewlett Packard.
+The default is to use the colors defined in the plot file or the
+ standard pen colors defined in the HP-GL/2 reference manual from
+ Hewlett Packard.
Fitting the Plot on the Page
-The -o fitplot
option specifies that the plot should be
-scaled to fit on the page:
+The -o fitplot
option specifies that the plot should be
+ scaled to fit on the page:
lp -o fitplot filename ENTER
lpr -o fitplot filename ENTER
-The default is to use the absolute distances specified in the plot
-file.
+
The default is to use the absolute distances specified in the plot
+ file.
NOTE:
-This feature depends upon an accurate plot size (PS
)
- command in the HP-GL/2 file. If no plot size is given in the file
- than the HP-GL/2 filter assumes the plot is ANSI E size.
+This feature depends upon an accurate plot size (PS
)
+ command in the HP-GL/2 file. If no plot size is given in the file than
+ the HP-GL/2 filter assumes the plot is ANSI E size.
Setting the Default Pen Width
-The -o penwidth=value
option specifies the default pen
-width for HP-GL/2 files:
+The -o penwidth=value
option specifies the default pen
+ width for HP-GL/2 files:
lp -o penwidth=value filename ENTER
lpr -o penwidth=value filename ENTER
-The pen width value
specifies the pen width in
-micrometers. The default value of 1000 produces lines that are 1
-millimeter in width. Specifying a pen width of 0 produces lines that
-are exactly 1 pixel wide.
+
The pen width value
specifies the pen width in
+ micrometers. The default value of 1000 produces lines that are 1
+ millimeter in width. Specifying a pen width of 0 produces lines that
+ are exactly 1 pixel wide.
NOTE:
-This option is ignored when the pen widths are set in the plot
-file.
+This option is ignored when the pen widths are set in the plot file.
Raw or Unfiltered Output
-The -o raw
option allows you to send files directly to
-a printer without filtering. This is sometimes required when printing
-from applications that provide their own "printer drivers" for your
-printer:
+The -o raw
option allows you to send files directly to a
+ printer without filtering. This is sometimes required when printing
+ from applications that provide their own "printer drivers" for your
+ printer:
lp -o raw filename ENTER
@@ -825,37 +834,37 @@ printer:
The -l
option can also be used with the lpr
- command to send files directly to a printer:
+ command to send files directly to a printer:
lpr -l filename ENTER
-4 - Saving Printer Options
-and Defaults
-This chapter describes how to save printer options for your printer
-and set your own default printer.
+4 - Saving Printer Options
+ and Defaults
+This chapter describes how to save printer options for your printer
+ and set your own default printer.
Printer Options
-Each printer supports a large number of options, which you learned
-about in Chapter 3, "Standard Printer
-Options". Rather than specifying these options each time you print
-a file, CUPS allows you to save them as "default" options for the
-printer.
-The lpoptions(1)
command saves the options for your
-printers. Like the lp
and lpr
commands, it
-accepts printer options using the -o
argument:
+Each printer supports a large number of options, which you learned
+ about in Chapter 3, "Standard Printer
+ Options". Rather than specifying these options each time you print
+ a file, CUPS allows you to save them as "default" options for the
+ printer.
+The lpoptions(1)
command saves the options for your
+ printers. Like the lp
and lpr
commands, it
+ accepts printer options using the -o
argument:
lpoptions -o media=A4 -o sides=two-sided-long-edge ENTER
lpoptions -o media=Legal -o scaling=100 ENTER
-Once saved, any lp
or lpr
command will use
-them when you print.
+Once saved, any lp
or lpr
command will use
+ them when you print.
Setting Options for a Specific Printer
-The previous example shows how to set the options for the default
-printer. The -p printer
option specifies the options are
-for another printer:
+The previous example shows how to set the options for the default
+ printer. The -p printer
option specifies the options are
+ for another printer:
lpoptions -p laserjet -o media=A4 -o sides=two-sided-long-edge ENTER
@@ -863,8 +872,8 @@ for another printer:
Viewing the Current Defaults
-The lpoptions
command can also be used to show the
-current options by not specifying any new options on the command-line:
+The lpoptions
command can also be used to show the
+ current options by not specifying any new options on the command-line:
lpoptions ENTER
@@ -874,28 +883,28 @@ media=Legal scaling=100
Setting the Default Printer
-The administrator normally will set a system-wide default printer
-that is normally used as the default printer by everyone. Use the
--d printer
option to set your own default printer:
+The administrator normally will set a system-wide default printer
+ that is normally used as the default printer by everyone. Use the
+-d printer
option to set your own default printer:
lpoptions -d deskjet ENTER
The printer can be local (deskjet
) or remote (
-deskjet@server
).
+deskjet@server).
Printer Instances
-Besides setting options for each print queue, CUPS supports
-printer instances which allow you to define several different sets
-of options for each printer. You specify a printer instance using the
-slash (/
) character:
+Besides setting options for each print queue, CUPS supports
+ printer instances which allow you to define several different sets
+ of options for each printer. You specify a printer instance using the
+ slash (/
) character:
lpoptions -p laserjet/duplex -o sides=two-sided-long-edge ENTER
lpoptions -p laserjet/legal -o media=Legal ENTER
-The lp
and lpr commands also understand this notation:
+The lp
and lpr commands also understand this notation:
lp -d laserjet/duplex filename ENTER
@@ -903,8 +912,8 @@ slash (/
) character:
Removing Instances
-Use the -x printer/instance
option to remove a printer
-instance that you no longer need:
+Use the -x printer/instance
option to remove a printer
+ instance that you no longer need:
lpoptions -x laserjet ENTER
@@ -912,86 +921,85 @@ instance that you no longer need:
lpoptions -x laserjet/legal ENTER
-The -x
option only removes the default options for that
-printer and instance; the original print queue will remain until
-deleted with the lpadmin(8)
command by the administrator.
+The -x
option only removes the default options for that
+ printer and instance; the original print queue will remain until
+ deleted with the lpadmin(8)
command by the administrator.
A - Software License Agreement
-Common UNIX Printing System License
-Agreement
+Common UNIX Printing System License
+ Agreement
Copyright 1997-2001 by Easy Software Products
44141 AIRPORT VIEW DR STE 204
HOLLYWOOD, MARYLAND 20636-3111 USA
Voice: +1.301.373.9600
-
Email: cups-info@cups.org
-
WWW: http://www.cups.org
+
Email: cups-info@cups.org
+
WWW: http://www.cups.org
Introduction
-The Common UNIX Printing SystemTM, ("CUPSTM"),
-is provided under the GNU General Public License ("GPL") and GNU
-Library General Public License ("LGPL"), Version 2. A copy of these
-licenses follow this introduction.
-The GNU LGPL applies to the CUPS API library, located in the "cups"
-subdirectory of the CUPS source distribution and in the
-"/usr/include/cups" directory and "libcups.a", "libcups.sl", or
-"libcups.so" files in the binary distributions.
-The GNU GPL applies to the remainder of the CUPS distribution,
-including the "pstoraster" filter which is based upon GNU Ghostscript
-5.50 and the "pdftops" filter which is based upon Xpdf 0.90.
-For those not familiar with the GNU GPL, the license basically
-allows you to:
-
-- Use the CUPS software at no charge.
-- Distribute verbatim copies of the software in source or binary
-form.
-- Sell verbatim copies of the software for a media fee, or sell
-support for the software.
-- Distribute or sell printer drivers and filters that use CUPS so
-long as source code is made available under the GPL.
-
-What this license does not allow you to do is make changes or
-add features to CUPS and then sell a binary distribution without source
-code. You must provide source for any new drivers, changes, or
-additions to the software, and all code must be provided under the GPL
-or LGPL as appropriate.
-The GNU LGPL relaxes the "link-to" restriction, allowing you to
-develop applications that use the CUPS API library under other licenses
-and/or conditions as appropriate for your application.
+The Common UNIX Printing SystemTM, ("CUPSTM"),
+ is provided under the GNU General Public License ("GPL") and GNU
+ Library General Public License ("LGPL"), Version 2. A copy of these
+ licenses follow this introduction.
+The GNU LGPL applies to the CUPS API library, located in the "cups"
+ subdirectory of the CUPS source distribution and in the
+ "/usr/include/cups" directory and "libcups.a", "libcups_s.a",
+ "libcups.sl", or "libcups.so" files in the binary distributions.
+The GNU GPL applies to the remainder of the CUPS distribution,
+ including the "pstoraster" filter which is based upon GNU Ghostscript
+ 5.50 and the "pdftops" filter which is based upon Xpdf 0.93a.
+For those not familiar with the GNU GPL, the license basically allows
+ you to:
+
+- Use the CUPS software at no charge.
+- Distribute verbatim copies of the software in source or binary form.
+- Sell verbatim copies of the software for a media fee, or sell
+ support for the software.
+- Distribute or sell printer drivers and filters that use CUPS so long
+ as source code is made available under the GPL.
+
+What this license does not allow you to do is make changes or
+ add features to CUPS and then sell a binary distribution without source
+ code. You must provide source for any new drivers, changes, or
+ additions to the software, and all code must be provided under the GPL
+ or LGPL as appropriate.
+The GNU LGPL relaxes the "link-to" restriction, allowing you to
+ develop applications that use the CUPS API library under other licenses
+ and/or conditions as appropriate for your application.
Trademarks
-Easy Software Products has trademarked the Common UNIX Printing
-System, CUPS, and CUPS logo. These names and logos may be used freely
-in any direct port or binary distribution of CUPS. To use them in
-derivative products, please contract Easy Software Products for written
-permission. Our intention is to protect the value of these trademarks
-and ensure that any derivative product meets the same high-quality
-standards as the original.
+Easy Software Products has trademarked the Common UNIX Printing
+ System, CUPS, and CUPS logo. These names and logos may be used freely
+ in any direct port or binary distribution of CUPS. To use them in
+ derivative products, please contract Easy Software Products for written
+ permission. Our intention is to protect the value of these trademarks
+ and ensure that any derivative product meets the same high-quality
+ standards as the original.
Binary Distribution Rights
-Easy Software Products also sells rights to the CUPS source code
-under a binary distribution license for vendors that are unable to
-release source code for their drivers, additions, and modifications to
-CUPS under the GNU GPL and LGPL. For information please contact us at
-the address shown above.
-The Common UNIX Printing System provides a "pstoraster" filter that
-utilizes the GNU GhostScript 5.50 core to convert PostScript files into
-a stream of raster images. For binary distribution licensing of this
-software, please contact:
Miles Jones
+Easy Software Products also sells rights to the CUPS source code
+ under a binary distribution license for vendors that are unable to
+ release source code for their drivers, additions, and modifications to
+ CUPS under the GNU GPL and LGPL. For information please contact us at
+ the address shown above.
+The Common UNIX Printing System provides a "pstoraster" filter that
+ utilizes the GNU GhostScript 5.50 core to convert PostScript files into
+ a stream of raster images. For binary distribution licensing of this
+ software, please contact:
Miles Jones
Director of Marketing
Artifex Software Inc.
454 Las Gallinas Ave., Suite 108
San Rafael, CA 94903 USA
Voice: +1.415.492.9861
Fax: +1.415.492.9862
-
EMail: info@arsoft.com
+
EMail: info@arsoft.com
-The "pdftops" filter is based on the Xpdf 0.90 software. For binary
-distribution licensing of this software, please contact:
+The "pdftops" filter is based on the Xpdf 0.93a software. For binary
+ distribution licensing of this software, please contact:
Derek B. Noonburg
-
Email: derekn@foolabs.com
-
WWW:
-http://www.foolabs.com/xpdf/
+
Email: derekn@foolabs.com
+
WWW:
+ http://www.foolabs.com/xpdf/
Support
-Easy Software Products sells software support for CUPS as well as a
-commercial printing product based on CUPS called ESP Print Pro. You can
-find out more at our web site:
+Easy Software Products sells software support for CUPS as well as a
+ commercial printing product based on CUPS called ESP Print Pro. You can
+ find out more at our web site:
http://www.easysw.com
@@ -1000,7 +1008,7 @@ find out more at our web site:
GNU GENERAL PUBLIC LICENSE
-Version 2, June 1991
+Version 2, June 1991
Copyright 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
@@ -1012,252 +1020,250 @@ copies of this license document, but changing it is not allowed.
Preamble
-The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it in
-new free programs; and that you know you can do these things.
-To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-We protect your rights with two steps: (1) copyright the software,
-and (2) offer you this license which gives you legal permission to
-copy, distribute and/or modify the software.
-Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on,
-we want its recipients to know that what they have is not the original,
-so that any problems introduced by others will not reflect on the
-original authors' reputations.
-Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-The precise terms and conditions for copying, distribution and
-modification follow.
+The licenses for most software are designed to take away your freedom
+ to share and change it. By contrast, the GNU General Public License is
+ intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users. This
+ General Public License applies to most of the Free Software
+ Foundation's software and to any other program whose authors commit to
+ using it. (Some other Free Software Foundation software is covered by
+ the GNU Library General Public License instead.) You can apply it to
+ your programs, too.
+When we speak of free software, we are referring to freedom, not
+ price. Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge for
+ this service if you wish), that you receive source code or can get it
+ if you want it, that you can change the software or use pieces of it in
+ new free programs; and that you know you can do these things.
+To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the rights.
+ These restrictions translate to certain responsibilities for you if you
+ distribute copies of the software, or if you modify it.
+For example, if you distribute copies of such a program, whether
+ gratis or for a fee, you must give the recipients all the rights that
+ you have. You must make sure that they, too, receive or can get the
+ source code. And you must show them these terms so they know their
+ rights.
+We protect your rights with two steps: (1) copyright the software,
+ and (2) offer you this license which gives you legal permission to
+ copy, distribute and/or modify the software.
+Also, for each author's protection and ours, we want to make certain
+ that everyone understands that there is no warranty for this free
+ software. If the software is modified by someone else and passed on, we
+ want its recipients to know that what they have is not the original, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.
+Finally, any free program is threatened constantly by software
+ patents. We wish to avoid the danger that redistributors of a free
+ program will individually obtain patent licenses, in effect making the
+ program proprietary. To prevent this, we have made it clear that any
+ patent must be licensed for everyone's free use or not licensed at all.
+The precise terms and conditions for copying, distribution and
+ modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-- This License applies to any program or other work which contains a
-notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the Program
-(independent of having been made by running the Program). Whether that
-is true depends on what the Program does.
-- You may copy and distribute verbatim copies of the Program's source
-code as you receive it, in any medium, provided that you conspicuously
-and appropriately publish on each copy an appropriate copyright notice
-and disclaimer of warranty; keep intact all the notices that refer to
-this License and to the absence of any warranty; and give any other
-recipients of the Program a copy of this License along with the
-Program.
-You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-- You may modify your copy or copies of the Program or any portion of
-it, thus forming a work based on the Program, and copy and distribute
-such modifications or work under the terms of Section 1 above, provided
-that you also meet all of these conditions:
+
- This License applies to any program or other work which contains a
+ notice placed by the copyright holder saying it may be distributed
+ under the terms of this General Public License. The "Program", below,
+ refers to any such program or work, and a "work based on the Program"
+ means either the Program or any derivative work under copyright law:
+ that is to say, a work containing the Program or a portion of it,
+ either verbatim or with modifications and/or translated into another
+ language. (Hereinafter, translation is included without limitation in
+ the term "modification".) Each licensee is addressed as "you".
+Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of running
+ the Program is not restricted, and the output from the Program is
+ covered only if its contents constitute a work based on the Program
+ (independent of having been made by running the Program). Whether that
+ is true depends on what the Program does.
+- You may copy and distribute verbatim copies of the Program's source
+ code as you receive it, in any medium, provided that you conspicuously
+ and appropriately publish on each copy an appropriate copyright notice
+ and disclaimer of warranty; keep intact all the notices that refer to
+ this License and to the absence of any warranty; and give any other
+ recipients of the Program a copy of this License along with the
+ Program.
+You may charge a fee for the physical act of transferring a copy, and
+ you may at your option offer warranty protection in exchange for a fee.
+- You may modify your copy or copies of the Program or any portion of
+ it, thus forming a work based on the Program, and copy and distribute
+ such modifications or work under the terms of Section 1 above, provided
+ that you also meet all of these conditions:
-- You must cause the modified files to carry prominent notices
-stating that you changed the files and the date of any change.
-- You must cause any work that you distribute or publish, that in
-whole or in part contains or is derived from the Program or any part
-thereof, to be licensed as a whole at no charge to all third parties
-under the terms of this License.
-- if the modified program normally reads commands interactively when
-run, you must cause it, when started running for such interactive use
-in the most ordinary way, to print or display an announcement including
-an appropriate copyright notice and a notice that there is no warranty
-(or else, saying that you provide a warranty) and that users may
-redistribute the program under these conditions, and telling the user
-how to view a copy of this License. (Exception: if the Program itself
-is interactive but does not normally print such an announcement, your
-work based on the Program is not required to print an announcement.)
+- You must cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change.
+- You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any part
+ thereof, to be licensed as a whole at no charge to all third parties
+ under the terms of this License.
+- if the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the most ordinary way, to print or display an announcement including
+ an appropriate copyright notice and a notice that there is no warranty
+ (or else, saying that you provide a warranty) and that users may
+ redistribute the program under these conditions, and telling the user
+ how to view a copy of this License. (Exception: if the Program itself
+ is interactive but does not normally print such an announcement, your
+ work based on the Program is not required to print an announcement.)
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-Thus, it is not the intent of this section to claim rights or
-contest your rights to work written entirely by you; rather, the intent
-is to exercise the right to control the distribution of derivative or
-collective works based on the Program.
-In addition, mere aggregation of another work not based on the
-Program with the Program (or with a work based on the Program) on a
-volume of a storage or distribution medium does not bring the other
-work under the scope of this License.
-- You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
+
These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Program,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Program, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote
+ it.
+Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Program.
+In addition, mere aggregation of another work not based on the
+ Program with the Program (or with a work based on the Program) on a
+ volume of a storage or distribution medium does not bring the other
+ work under the scope of this License.
+ - You may copy and distribute the Program (or a work based on it,
+ under Section 2) in object code or executable form under the terms of
+ Sections 1 and 2 above provided that you also do one of the following:
-- Accompany it with the complete corresponding machine-readable
-source code, which must be distributed under the terms of Sections 1
-and 2 above on a medium customarily used for software interchange; or,
-- Accompany it with a written offer, valid for at least three years,
-to give any third party, for a charge no more than your cost of
-physically performing source distribution, a complete machine-readable
-copy of the corresponding source code, to be distributed under the
-terms of Sections 1 and 2 above on a medium customarily used for
-software interchange; or,
-- Accompany it with the information you received as to the offer to
-distribute corresponding source code. (This alternative is allowed
-only for noncommercial distribution and only if you received the
-program in object code or executable form with such an offer, in accord
-with Subsection b above.)
+- Accompany it with the complete corresponding machine-readable source
+ code, which must be distributed under the terms of Sections 1 and 2
+ above on a medium customarily used for software interchange; or,
+- Accompany it with a written offer, valid for at least three years,
+ to give any third party, for a charge no more than your cost of
+ physically performing source distribution, a complete machine-readable
+ copy of the corresponding source code, to be distributed under the
+ terms of Sections 1 and 2 above on a medium customarily used for
+ software interchange; or,
+- Accompany it with the information you received as to the offer to
+ distribute corresponding source code. (This alternative is allowed only
+ for noncommercial distribution and only if you received the program in
+ object code or executable form with such an offer, in accord with
+ Subsection b above.)
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to control
-compilation and installation of the executable. However, as a special
-exception, the source code distributed need not include anything that
-is normally distributed (in either source or binary form) with the
-major components (compiler, kernel, and so on) of the operating system
-on which the executable runs, unless that component itself accompanies
-the executable.
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent access
-to copy the source code from the same place counts as distribution of
-the source code, even though third parties are not compelled to copy
-the source along with the object code.
-- You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt otherwise
-to copy, modify, sublicense or distribute the Program is void, and will
-automatically terminate your rights under this License. However,
-parties who have received copies, or rights, from you under this
-License will not have their licenses terminated so long as such parties
-remain in full compliance.
-- You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying the
-Program or works based on it.
-- Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-- If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-If any portion of this section is held invalid or unenforceable
-under any particular circumstance, the balance of the section is
-intended to apply and the section as a whole is intended to apply in
-other circumstances.
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-This section is intended to make thoroughly clear what is believed
-to be a consequence of the rest of this License.
-- If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License may
-add an explicit geographical distribution limitation excluding those
-countries, so that distribution is permitted only in or among countries
-not thus excluded. In such case, this License incorporates the
-limitation as if written in the body of this License.
-- The Free Software Foundation may publish revised and/or new
-versions of the General Public License from time to time. Such new
-versions will be similar in spirit to the present version, but may
-differ in detail to address new problems or concerns.
-Each version is given a distinguishing version number. If the
-Program specifies a version number of this License which applies to it
-and "any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Program does not specify a
-version number of this License, you may choose any version ever
-published by the Free Software Foundation.
-- If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the
-author to ask for permission. For software which is copyrighted by the
-Free Software Foundation, write to the Free Software Foundation; we
-sometimes make exceptions for this. Our decision will be guided by the
-two goals of preserving the free status of all derivatives of our free
-software and of promoting the sharing and reuse of software generally.
+The source code for a work means the preferred form of the work for
+ making modifications to it. For an executable work, complete source
+ code means all the source code for all modules it contains, plus any
+ associated interface definition files, plus the scripts used to control
+ compilation and installation of the executable. However, as a special
+ exception, the source code distributed need not include anything that
+ is normally distributed (in either source or binary form) with the
+ major components (compiler, kernel, and so on) of the operating system
+ on which the executable runs, unless that component itself accompanies
+ the executable.
+If distribution of executable or object code is made by offering
+ access to copy from a designated place, then offering equivalent access
+ to copy the source code from the same place counts as distribution of
+ the source code, even though third parties are not compelled to copy
+ the source along with the object code.
+- You may not copy, modify, sublicense, or distribute the Program
+ except as expressly provided under this License. Any attempt otherwise
+ to copy, modify, sublicense or distribute the Program is void, and will
+ automatically terminate your rights under this License. However,
+ parties who have received copies, or rights, from you under this
+ License will not have their licenses terminated so long as such parties
+ remain in full compliance.
+- You are not required to accept this License, since you have not
+ signed it. However, nothing else grants you permission to modify or
+ distribute the Program or its derivative works. These actions are
+ prohibited by law if you do not accept this License. Therefore, by
+ modifying or distributing the Program (or any work based on the
+ Program), you indicate your acceptance of this License to do so, and
+ all its terms and conditions for copying, distributing or modifying the
+ Program or works based on it.
+- Each time you redistribute the Program (or any work based on the
+ Program), the recipient automatically receives a license from the
+ original licensor to copy, distribute or modify the Program subject to
+ these terms and conditions. You may not impose any further restrictions
+ on the recipients' exercise of the rights granted herein. You are not
+ responsible for enforcing compliance by third parties to this License.
+- If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent issues),
+ conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot
+ distribute so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you
+ may not distribute the Program at all. For example, if a patent license
+ would not permit royalty-free redistribution of the Program by all
+ those who receive copies directly or indirectly through you, then the
+ only way you could satisfy both it and this License would be to refrain
+ entirely from distribution of the Program.
+If any portion of this section is held invalid or unenforceable under
+ any particular circumstance, the balance of the section is intended to
+ apply and the section as a whole is intended to apply in other
+ circumstances.
+It is not the purpose of this section to induce you to infringe any
+ patents or other property right claims or to contest validity of any
+ such claims; this section has the sole purpose of protecting the
+ integrity of the free software distribution system, which is
+ implemented by public license practices. Many people have made generous
+ contributions to the wide range of software distributed through that
+ system in reliance on consistent application of that system; it is up
+ to the author/donor to decide if he or she is willing to distribute
+ software through any other system and a licensee cannot impose that
+ choice.
+This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.
+- If the distribution and/or use of the Program is restricted in
+ certain countries either by patents or by copyrighted interfaces, the
+ original copyright holder who places the Program under this License may
+ add an explicit geographical distribution limitation excluding those
+ countries, so that distribution is permitted only in or among countries
+ not thus excluded. In such case, this License incorporates the
+ limitation as if written in the body of this License.
+- The Free Software Foundation may publish revised and/or new versions
+ of the General Public License from time to time. Such new versions will
+ be similar in spirit to the present version, but may differ in detail
+ to address new problems or concerns.
+Each version is given a distinguishing version number. If the Program
+ specifies a version number of this License which applies to it and "any
+ later version", you have the option of following the terms and
+ conditions either of that version or of any later version published by
+ the Free Software Foundation. If the Program does not specify a version
+ number of this License, you may choose any version ever published by
+ the Free Software Foundation.
+- If you wish to incorporate parts of the Program into other free
+ programs whose distribution conditions are different, write to the
+ author to ask for permission. For software which is copyrighted by the
+ Free Software Foundation, write to the Free Software Foundation; we
+ sometimes make exceptions for this. Our decision will be guided by the
+ two goals of preserving the free status of all derivatives of our free
+ software and of promoting the sharing and reuse of software generally.
NO WARRANTY
-- BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
- EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
-EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS
-WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
+- BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+ FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+ OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+ PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
+ EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
+ YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+ NECESSARY SERVICING, REPAIR OR CORRECTION.
+- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+ AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU
+ FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+ PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+ FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.
END OF TERMS AND CONDITIONS
GNU LIBRARY GENERAL PUBLIC LICENSE
-Version 2, June 1991
+Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
@@ -1268,376 +1274,372 @@ of this license document, but changing it is not allowed.
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
-The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-This license, the Library General Public License, applies to some
-specially designated Free Software Foundation software, and to any
-other libraries whose authors decide to use it. You can use it for
-your libraries, too.
-When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it in
-new free programs; and that you know you can do these things.
-To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the library, or if you modify it.
-For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link a program with the library, you must provide
-complete object files to the recipients so that they can relink them
-with the library, after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-Our method of protecting your rights has two steps: (1) copyright
-the library, and (2) offer you this license which gives you legal
-permission to copy, distribute and/or modify the library.
-Also, for each distributor's protection, we want to make certain
-that everyone understands that there is no warranty for this free
-library. If the library is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original
-version, so that any problems introduced by others will not reflect on
-the original authors' reputations.
-Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that companies distributing free
-software will individually obtain patent licenses, thus in effect
-transforming the program into proprietary software. To prevent this,
-we have made it clear that any patent must be licensed for everyone's
-free use or not licensed at all.
-Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License, which was designed for utility
-programs. This license, the GNU Library General Public License,
-applies to certain designated libraries. This license is quite
-different from the ordinary one; be sure to read it in full, and don't
-assume that anything in it is the same as in the ordinary license.
-The reason we have a separate public license for some libraries is
-that they blur the distinction we usually make between modifying or
-adding to a program and simply using it. Linking a program with a
-library, without changing the library, is in some sense simply using
-the library, and is analogous to running a utility program or
-application program. However, in a textual and legal sense, the linked
-executable is a combined work, a derivative of the original library,
-and the ordinary General Public License treats it as such.
-Because of this blurred distinction, using the ordinary General
-Public License for libraries did not effectively promote software
-sharing, because most developers did not use the libraries. We
-concluded that weaker conditions might promote sharing better.
-However, unrestricted linking of non-free programs would deprive the
-users of those programs of all benefit from the free status of the
-libraries themselves. This Library General Public License is intended
-to permit developers of non-free programs to use free libraries, while
-preserving your freedom as a user of such programs to change the free
-libraries that are incorporated in them. (We have not seen how to
-achieve this as regards changes in header files, but we have achieved
-it as regards changes in the actual functions of the Library.) The
-hope is that this will lead to faster development of free libraries.
-The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, while the latter only
-works together with the library.
-Note that it is possible for a library to be covered by the ordinary
-General Public License rather than by this special one.
+The licenses for most software are designed to take away your freedom
+ to share and change it. By contrast, the GNU General Public Licenses
+ are intended to guarantee your freedom to share and change free
+ software--to make sure the software is free for all its users.
+This license, the Library General Public License, applies to some
+ specially designated Free Software Foundation software, and to any
+ other libraries whose authors decide to use it. You can use it for your
+ libraries, too.
+When we speak of free software, we are referring to freedom, not
+ price. Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge for
+ this service if you wish), that you receive source code or can get it
+ if you want it, that you can change the software or use pieces of it in
+ new free programs; and that you know you can do these things.
+To protect your rights, we need to make restrictions that forbid
+ anyone to deny you these rights or to ask you to surrender the rights.
+ These restrictions translate to certain responsibilities for you if you
+ distribute copies of the library, or if you modify it.
+For example, if you distribute copies of the library, whether gratis
+ or for a fee, you must give the recipients all the rights that we gave
+ you. You must make sure that they, too, receive or can get the source
+ code. If you link a program with the library, you must provide complete
+ object files to the recipients so that they can relink them with the
+ library, after making changes to the library and recompiling it. And
+ you must show them these terms so they know their rights.
+Our method of protecting your rights has two steps: (1) copyright the
+ library, and (2) offer you this license which gives you legal
+ permission to copy, distribute and/or modify the library.
+Also, for each distributor's protection, we want to make certain that
+ everyone understands that there is no warranty for this free library.
+ If the library is modified by someone else and passed on, we want its
+ recipients to know that what they have is not the original version, so
+ that any problems introduced by others will not reflect on the original
+ authors' reputations.
+Finally, any free program is threatened constantly by software
+ patents. We wish to avoid the danger that companies distributing free
+ software will individually obtain patent licenses, thus in effect
+ transforming the program into proprietary software. To prevent this, we
+ have made it clear that any patent must be licensed for everyone's free
+ use or not licensed at all.
+Most GNU software, including some libraries, is covered by the
+ ordinary GNU General Public License, which was designed for utility
+ programs. This license, the GNU Library General Public License, applies
+ to certain designated libraries. This license is quite different from
+ the ordinary one; be sure to read it in full, and don't assume that
+ anything in it is the same as in the ordinary license.
+The reason we have a separate public license for some libraries is
+ that they blur the distinction we usually make between modifying or
+ adding to a program and simply using it. Linking a program with a
+ library, without changing the library, is in some sense simply using
+ the library, and is analogous to running a utility program or
+ application program. However, in a textual and legal sense, the linked
+ executable is a combined work, a derivative of the original library,
+ and the ordinary General Public License treats it as such.
+Because of this blurred distinction, using the ordinary General
+ Public License for libraries did not effectively promote software
+ sharing, because most developers did not use the libraries. We
+ concluded that weaker conditions might promote sharing better.
+However, unrestricted linking of non-free programs would deprive the
+ users of those programs of all benefit from the free status of the
+ libraries themselves. This Library General Public License is intended
+ to permit developers of non-free programs to use free libraries, while
+ preserving your freedom as a user of such programs to change the free
+ libraries that are incorporated in them. (We have not seen how to
+ achieve this as regards changes in header files, but we have achieved
+ it as regards changes in the actual functions of the Library.) The hope
+ is that this will lead to faster development of free libraries.
+The precise terms and conditions for copying, distribution and
+ modification follow. Pay close attention to the difference between a
+ "work based on the library" and a "work that uses the library". The
+ former contains code derived from the library, while the latter only
+ works together with the library.
+Note that it is possible for a library to be covered by the ordinary
+ General Public License rather than by this special one.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-0. This License Agreement applies to any software
-library which contains a notice placed by the copyright holder or other
-authorized party saying it may be distributed under the terms of this
-Library General Public License (also called "this License"). Each
-licensee is addressed as "you".
-A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-"Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control
-compilation and installation of the library.
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does and
-what the program that uses the Library does.
-1. You may copy and distribute verbatim copies of
-the Library's complete source code as you receive it, in any medium,
-provided that you conspicuously and appropriately publish on each copy
-an appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the Library.
-You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-2. You may modify your copy or copies of the
-Library or any portion of it, thus forming a work based on the Library,
-and copy and distribute such modifications or work under the terms of
-Section 1 above, provided that you also meet all of these conditions:
+0. This License Agreement applies to any software
+ library which contains a notice placed by the copyright holder or other
+ authorized party saying it may be distributed under the terms of this
+ Library General Public License (also called "this License"). Each
+ licensee is addressed as "you".
+A "library" means a collection of software functions and/or data
+ prepared so as to be conveniently linked with application programs
+ (which use some of those functions and data) to form executables.
+The "Library", below, refers to any such software library or work
+ which has been distributed under these terms. A "work based on the
+ Library" means either the Library or any derivative work under
+ copyright law: that is to say, a work containing the Library or a
+ portion of it, either verbatim or with modifications and/or translated
+ straightforwardly into another language. (Hereinafter, translation is
+ included without limitation in the term "modification".)
+"Source code" for a work means the preferred form of the work for
+ making modifications to it. For a library, complete source code means
+ all the source code for all modules it contains, plus any associated
+ interface definition files, plus the scripts used to control
+ compilation and installation of the library.
+Activities other than copying, distribution and modification are not
+ covered by this License; they are outside its scope. The act of running
+ a program using the Library is not restricted, and output from such a
+ program is covered only if its contents constitute a work based on the
+ Library (independent of the use of the Library in a tool for writing
+ it). Whether that is true depends on what the Library does and what the
+ program that uses the Library does.
+1. You may copy and distribute verbatim copies of
+ the Library's complete source code as you receive it, in any medium,
+ provided that you conspicuously and appropriately publish on each copy
+ an appropriate copyright notice and disclaimer of warranty; keep intact
+ all the notices that refer to this License and to the absence of any
+ warranty; and distribute a copy of this License along with the Library.
+You may charge a fee for the physical act of transferring a copy, and
+ you may at your option offer warranty protection in exchange for a fee.
+2. You may modify your copy or copies of the Library
+ or any portion of it, thus forming a work based on the Library, and
+ copy and distribute such modifications or work under the terms of
+ Section 1 above, provided that you also meet all of these conditions:
-- The modified work must itself be a software library.
+- The modified work must itself be a software library.
-- You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
+- You must cause the files modified to carry prominent notices stating
+ that you changed the files and the date of any change.
-- You must cause the whole of the work to be licensed at no charge
-to all third parties under the terms of this License.
+- You must cause the whole of the work to be licensed at no charge to
+ all third parties under the terms of this License.
-- If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses the
-facility, other than as an argument passed when the facility is
-invoked, then you must make a good faith effort to ensure that, in the
-event an application does not supply such function or table, the
-facility still operates, and performs whatever part of its purpose
-remains meaningful.
-(For example, a function in a library to compute square roots has a
-purpose that is entirely well-defined independent of the application.
- Therefore, Subsection 2d requires that any application-supplied
-function or table used by this function must be optional: if the
-application does not supply it, the square root function must still
-compute square roots.)
+- If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses the
+ facility, other than as an argument passed when the facility is
+ invoked, then you must make a good faith effort to ensure that, in the
+ event an application does not supply such function or table, the
+ facility still operates, and performs whatever part of its purpose
+ remains meaningful.
+(For example, a function in a library to compute square roots has a
+ purpose that is entirely well-defined independent of the application.
+ Therefore, Subsection 2d requires that any application-supplied
+ function or table used by this function must be optional: if the
+ application does not supply it, the square root function must still
+ compute square roots.)
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-Thus, it is not the intent of this section to claim rights or
-contest your rights to work written entirely by you; rather, the intent
-is to exercise the right to control the distribution of derivative or
-collective works based on the Library.
-In addition, mere aggregation of another work not based on the
-Library with the Library (or with a work based on the Library) on a
-volume of a storage or distribution medium does not bring the other
-work under the scope of this License.
-3. You may opt to apply the terms of the ordinary
-GNU General Public License instead of this License to a given copy of
-the Library. To do this, you must alter all the notices that refer to
-this License, so that they refer to the ordinary GNU General Public
-License, version 2, instead of to this License. (If a newer version
-than version 2 of the ordinary GNU General Public License has appeared,
-then you can specify that version instead if you wish.) Do not make
-any other change in these notices.
-Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-This option is useful when you wish to copy part of the code of the
-Library into a program that is not a library.
-4. You may copy and distribute the Library (or a
-portion or derivative of it, under Section 2) in object code or
-executable form under the terms of Sections 1 and 2 above provided that
-you accompany it with the complete corresponding machine-readable
-source code, which must be distributed under the terms of Sections 1
-and 2 above on a medium customarily used for software interchange.
-If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to distribute
-the source code, even though third parties are not compelled to copy
-the source along with the object code.
-5. A program that contains no derivative of any
-portion of the Library, but is designed to work with the Library by
-being compiled or linked with it, is called a "work that uses the
-Library". Such a work, in isolation, is not a derivative work of the
-Library, and therefore falls outside the scope of this License.
-However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License. Section
-6 states terms for distribution of such executables.
-When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6, whether
-or not they are linked directly with the Library itself.
-6. As an exception to the Sections above, you may
-also compile or link a "work that uses the Library" with the Library to
-produce a work containing portions of the Library, and distribute that
-work under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
+These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the Library,
+ and can be reasonably considered independent and separate works in
+ themselves, then this License, and its terms, do not apply to those
+ sections when you distribute them as separate works. But when you
+ distribute the same sections as part of a whole which is a work based
+ on the Library, the distribution of the whole must be on the terms of
+ this License, whose permissions for other licensees extend to the
+ entire whole, and thus to each and every part regardless of who wrote
+ it.
+Thus, it is not the intent of this section to claim rights or contest
+ your rights to work written entirely by you; rather, the intent is to
+ exercise the right to control the distribution of derivative or
+ collective works based on the Library.
+In addition, mere aggregation of another work not based on the
+ Library with the Library (or with a work based on the Library) on a
+ volume of a storage or distribution medium does not bring the other
+ work under the scope of this License.
+3. You may opt to apply the terms of the ordinary
+ GNU General Public License instead of this License to a given copy of
+ the Library. To do this, you must alter all the notices that refer to
+ this License, so that they refer to the ordinary GNU General Public
+ License, version 2, instead of to this License. (If a newer version
+ than version 2 of the ordinary GNU General Public License has appeared,
+ then you can specify that version instead if you wish.) Do not make any
+ other change in these notices.
+Once this change is made in a given copy, it is irreversible for that
+ copy, so the ordinary GNU General Public License applies to all
+ subsequent copies and derivative works made from that copy.
+This option is useful when you wish to copy part of the code of the
+ Library into a program that is not a library.
+4. You may copy and distribute the Library (or a
+ portion or derivative of it, under Section 2) in object code or
+ executable form under the terms of Sections 1 and 2 above provided that
+ you accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections 1
+ and 2 above on a medium customarily used for software interchange.
+If distribution of object code is made by offering access to copy
+ from a designated place, then offering equivalent access to copy the
+ source code from the same place satisfies the requirement to distribute
+ the source code, even though third parties are not compelled to copy
+ the source along with the object code.
+5. A program that contains no derivative of any
+ portion of the Library, but is designed to work with the Library by
+ being compiled or linked with it, is called a "work that uses the
+ Library". Such a work, in isolation, is not a derivative work of the
+ Library, and therefore falls outside the scope of this License.
+However, linking a "work that uses the Library" with the Library
+ creates an executable that is a derivative of the Library (because it
+ contains portions of the Library), rather than a "work that uses the
+ library". The executable is therefore covered by this License. Section
+ 6 states terms for distribution of such executables.
+When a "work that uses the Library" uses material from a header file
+ that is part of the Library, the object code for the work may be a
+ derivative work of the Library even though the source code is not.
+ Whether this is true is especially significant if the work can be
+ linked without the Library, or if the work is itself a library. The
+ threshold for this to be true is not precisely defined by law.
+If such an object file uses only numerical parameters, data structure
+ layouts and accessors, and small macros and small inline functions (ten
+ lines or less in length), then the use of the object file is
+ unrestricted, regardless of whether it is legally a derivative work.
+ (Executables containing this object code plus portions of the Library
+ will still fall under Section 6.)
+Otherwise, if the work is a derivative of the Library, you may
+ distribute the object code for the work under the terms of Section 6.
+ Any executables containing that work also fall under Section 6, whether
+ or not they are linked directly with the Library itself.
+6. As an exception to the Sections above, you may
+ also compile or link a "work that uses the Library" with the Library to
+ produce a work containing portions of the Library, and distribute that
+ work under terms of your choice, provided that the terms permit
+ modification of the work for the customer's own use and reverse
+ engineering for debugging such modifications.
+You must give prominent notice with each copy of the work that the
+ Library is used in it and that the Library and its use are covered by
+ this License. You must supply a copy of this License. If the work
+ during execution displays copyright notices, you must include the
+ copyright notice for the Library among them, as well as a reference
+ directing the user to the copy of this License. Also, you must do one
+ of these things:
-- Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that uses
-the Library", as object code and/or source code, so that the user can
-modify the Library and then relink to produce a modified executable
-containing the modified Library. (It is understood that the user who
-changes the contents of definitions files in the Library will not
-necessarily be able to recompile the application to use the modified
-definitions.)
+- Accompany the work with the complete corresponding machine-readable
+ source code for the Library including whatever changes were used in the
+ work (which must be distributed under Sections 1 and 2 above); and, if
+ the work is an executable linked with the Library, with the complete
+ machine-readable "work that uses the Library", as object code and/or
+ source code, so that the user can modify the Library and then relink to
+ produce a modified executable containing the modified Library. (It is
+ understood that the user who changes the contents of definitions files
+ in the Library will not necessarily be able to recompile the
+ application to use the modified definitions.)
-- Accompany the work with a written offer, valid for at least three
-years, to give the same user the materials specified in Subsection 6a,
-above, for a charge no more than the cost of performing this
-distribution.
+- Accompany the work with a written offer, valid for at least three
+ years, to give the same user the materials specified in Subsection 6a,
+ above, for a charge no more than the cost of performing this
+ distribution.
-- If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
+- If distribution of the work is made by offering access to copy from
+ a designated place, offer equivalent access to copy the above specified
+ materials from the same place.
-- Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
+- Verify that the user has already received a copy of these materials
+ or that you have already sent this user a copy.
-For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the source code distributed need not include anything that is normally
-distributed (in either source or binary form) with the major components
-(compiler, kernel, and so on) of the operating system on which the
-executable runs, unless that component itself accompanies the
-executable.
-It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-7. You may place library facilities that are a work
-based on the Library side-by-side in a single library together with
-other library facilities not covered by this License, and distribute
-such a combined library, provided that the separate distribution of the
-work based on the Library and of the other library facilities is
-otherwise permitted, and provided that you do these two things:
+For an executable, the required form of the "work that uses the
+ Library" must include any data and utility programs needed for
+ reproducing the executable from it. However, as a special exception,
+ the source code distributed need not include anything that is normally
+ distributed (in either source or binary form) with the major components
+ (compiler, kernel, and so on) of the operating system on which the
+ executable runs, unless that component itself accompanies the
+ executable.
+It may happen that this requirement contradicts the license
+ restrictions of other proprietary libraries that do not normally
+ accompany the operating system. Such a contradiction means you cannot
+ use both them and the Library together in an executable that you
+ distribute.
+7. You may place library facilities that are a work
+ based on the Library side-by-side in a single library together with
+ other library facilities not covered by this License, and distribute
+ such a combined library, provided that the separate distribution of the
+ work based on the Library and of the other library facilities is
+ otherwise permitted, and provided that you do these two things:
-- Accompany the combined library with a copy of the same work based
-on the Library, uncombined with any other library facilities. This
-must be distributed under the terms of the Sections above.
+- Accompany the combined library with a copy of the same work based on
+ the Library, uncombined with any other library facilities. This must be
+ distributed under the terms of the Sections above.
-- Give prominent notice with the combined library of the fact that
-part of it is a work based on the Library, and explaining where to
-find the accompanying uncombined form of the same work.
+- Give prominent notice with the combined library of the fact that
+ part of it is a work based on the Library, and explaining where to find
+ the accompanying uncombined form of the same work.
-8. You may not copy, modify, sublicense, link with,
-or distribute the Library except as expressly provided under this
-License. Any attempt otherwise to copy, modify, sublicense, link with,
-or distribute the Library is void, and will automatically terminate
-your rights under this License. However, parties who have received
-copies, or rights, from you under this License will not have their
-licenses terminated so long as such parties remain in full compliance.
-9. You are not required to accept this License,
-since you have not signed it. However, nothing else grants you
-permission to modify or distribute the Library or its derivative works.
- These actions are prohibited by law if you do not accept this License.
- Therefore, by modifying or distributing the Library (or any work based
-on the Library), you indicate your acceptance of this License to do so,
-and all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-10. Each time you redistribute the Library (or any
-work based on the Library), the recipient automatically receives a
-license from the original licensor to copy, distribute, link with or
-modify the Library subject to these terms and conditions. You may not
-impose any further restrictions on the recipients' exercise of the
-rights granted herein. You are not responsible for enforcing compliance
-by third parties to this License.
-11. If, as a consequence of a court judgment or
-allegation of patent infringement or for any other reason (not limited
-to patent issues), conditions are imposed on you (whether by court
-order, agreement or otherwise) that contradict the conditions of this
-License, they do not excuse you from the conditions of this License.
- If you cannot distribute so as to satisfy simultaneously your
-obligations under this License and any other pertinent obligations,
-then as a consequence you may not distribute the Library at all. For
-example, if a patent license would not permit royalty-free
-redistribution of the Library by all those who receive copies directly
-or indirectly through you, then the only way you could satisfy both it
-and this License would be to refrain entirely from distribution of the
-Library.
-If any portion of this section is held invalid or unenforceable
-under any particular circumstance, the balance of the section is
-intended to apply, and the section as a whole is intended to apply in
-other circumstances.
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is implemented
-by public license practices. Many people have made generous
-contributions to the wide range of software distributed through that
-system in reliance on consistent application of that system; it is up
-to the author/donor to decide if he or she is willing to distribute
-software through any other system and a licensee cannot impose that
-choice.
-This section is intended to make thoroughly clear what is believed
-to be a consequence of the rest of this License.
-12. If the distribution and/or use of the Library
-is restricted in certain countries either by patents or by copyrighted
-interfaces, the original copyright holder who places the Library under
-this License may add an explicit geographical distribution limitation
-excluding those countries, so that distribution is permitted only in or
-among countries not thus excluded. In such case, this License
-incorporates the limitation as if written in the body of this License.
-13. The Free Software Foundation may publish
-revised and/or new versions of the Library General Public License from
-time to time. Such new versions will be similar in spirit to the
-present version, but may differ in detail to address new problems or
-concerns.
-Each version is given a distinguishing version number. If the
-Library specifies a version number of this License which applies to it
-and "any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-14. If you wish to incorporate parts of the Library
-into other free programs whose distribution conditions are incompatible
-with these, write to the author to ask for permission. For software
-which is copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
+8. You may not copy, modify, sublicense, link with,
+ or distribute the Library except as expressly provided under this
+ License. Any attempt otherwise to copy, modify, sublicense, link with,
+ or distribute the Library is void, and will automatically terminate
+ your rights under this License. However, parties who have received
+ copies, or rights, from you under this License will not have their
+ licenses terminated so long as such parties remain in full compliance.
+9. You are not required to accept this License,
+ since you have not signed it. However, nothing else grants you
+ permission to modify or distribute the Library or its derivative works.
+ These actions are prohibited by law if you do not accept this License.
+ Therefore, by modifying or distributing the Library (or any work based
+ on the Library), you indicate your acceptance of this License to do so,
+ and all its terms and conditions for copying, distributing or modifying
+ the Library or works based on it.
+10. Each time you redistribute the Library (or any
+ work based on the Library), the recipient automatically receives a
+ license from the original licensor to copy, distribute, link with or
+ modify the Library subject to these terms and conditions. You may not
+ impose any further restrictions on the recipients' exercise of the
+ rights granted herein. You are not responsible for enforcing compliance
+ by third parties to this License.
+11. If, as a consequence of a court judgment or
+ allegation of patent infringement or for any other reason (not limited
+ to patent issues), conditions are imposed on you (whether by court
+ order, agreement or otherwise) that contradict the conditions of this
+ License, they do not excuse you from the conditions of this License. If
+ you cannot distribute so as to satisfy simultaneously your obligations
+ under this License and any other pertinent obligations, then as a
+ consequence you may not distribute the Library at all. For example, if
+ a patent license would not permit royalty-free redistribution of the
+ Library by all those who receive copies directly or indirectly through
+ you, then the only way you could satisfy both it and this License would
+ be to refrain entirely from distribution of the Library.
+If any portion of this section is held invalid or unenforceable under
+ any particular circumstance, the balance of the section is intended to
+ apply, and the section as a whole is intended to apply in other
+ circumstances.
+It is not the purpose of this section to induce you to infringe any
+ patents or other property right claims or to contest validity of any
+ such claims; this section has the sole purpose of protecting the
+ integrity of the free software distribution system which is implemented
+ by public license practices. Many people have made generous
+ contributions to the wide range of software distributed through that
+ system in reliance on consistent application of that system; it is up
+ to the author/donor to decide if he or she is willing to distribute
+ software through any other system and a licensee cannot impose that
+ choice.
+This section is intended to make thoroughly clear what is believed to
+ be a consequence of the rest of this License.
+12. If the distribution and/or use of the Library is
+ restricted in certain countries either by patents or by copyrighted
+ interfaces, the original copyright holder who places the Library under
+ this License may add an explicit geographical distribution limitation
+ excluding those countries, so that distribution is permitted only in or
+ among countries not thus excluded. In such case, this License
+ incorporates the limitation as if written in the body of this License.
+13. The Free Software Foundation may publish revised
+ and/or new versions of the Library General Public License from time to
+ time. Such new versions will be similar in spirit to the present
+ version, but may differ in detail to address new problems or concerns.
+Each version is given a distinguishing version number. If the Library
+ specifies a version number of this License which applies to it and "any
+ later version", you have the option of following the terms and
+ conditions either of that version or of any later version published by
+ the Free Software Foundation. If the Library does not specify a license
+ version number, you may choose any version ever published by the Free
+ Software Foundation.
+14. If you wish to incorporate parts of the Library
+ into other free programs whose distribution conditions are incompatible
+ with these, write to the author to ask for permission. For software
+ which is copyrighted by the Free Software Foundation, write to the Free
+ Software Foundation; we sometimes make exceptions for this. Our
+ decision will be guided by the two goals of preserving the free status
+ of all derivatives of our free software and of promoting the sharing
+ and reuse of software generally.
NO WARRANTY
-15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE,
-THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT
-WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
-OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU
-ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW
-OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY
-WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE
-LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL
-OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE,
+ THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT
+ WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
+ OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU
+ ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+ AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO
+ MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL
+ OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+ LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+ RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+ SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGES.
END OF TERMS AND CONDITIONS
diff --git a/doc/sum.pdf b/doc/sum.pdf
index 34bdc62d90..4426de5a98 100644
Binary files a/doc/sum.pdf and b/doc/sum.pdf differ
diff --git a/doc/sum.shtml b/doc/sum.shtml
index 46e689c3a0..fd15b01233 100644
--- a/doc/sum.shtml
+++ b/doc/sum.shtml
@@ -2,7 +2,7 @@
-
+
CUPS Software Users Manual
@@ -11,7 +11,7 @@
Preface
This software users manual describes how to use the Common UNIX Printing
-SystemTM ("CUPSTM") Version 1.1.7.
+SystemTM ("CUPSTM") Version 1.2.0.
2 References
2.1 CUPS Documentation
-The following CUPS documentation is referenced by this document:
+The following CUPS documentation is referenced by this document:
-- CUPS-CMP-1.1: CUPS Configuration Management Plan
-- CUPS-IDD-1.1: CUPS System Interface Design Description
-- CUPS-IPP-1.1: CUPS Implementation of IPP
-- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
-- CUPS-SDD-1.1: CUPS Software Design Description
-- CUPS-SPM-1.1.x: CUPS Software Programming Manual
-- CUPS-SSR-1.1: CUPS Software Security Report
-- CUPS-STP-1.1: CUPS Software Test Plan
-- CUPS-SUM-1.1.x: CUPS Software Users Manual
-- CUPS-SVD-1.1: CUPS Software Version Description
+- CUPS-CMP-1.1: CUPS Configuration Management Plan
+- CUPS-IDD-1.1: CUPS System Interface Design Description
+- CUPS-IPP-1.1: CUPS Implementation of IPP
+- CUPS-SAM-1.1.x: CUPS Software Administrators Manual
+- CUPS-SDD-1.1: CUPS Software Design Description
+- CUPS-SPM-1.1.x: CUPS Software Programming Manual
+- CUPS-SSR-1.1: CUPS Software Security Report
+- CUPS-STP-1.1: CUPS Software Test Plan
+- CUPS-SUM-1.1.x: CUPS Software Users Manual
+- CUPS-SVD-1.1: CUPS Software Version Description
2.2 Other Documents
-The following non-CUPS documents are referenced by this document:
+The following non-CUPS documents are referenced by this document:
-
-Adobe PostScript Printer Description File Format Specification,
- Version 4.3.
+Adobe PostScript Printer Description File Format Specification, Version
+ 4.3.
-
-Adobe PostScript Language Reference, Third Edition.
-- IPP: Job and Printer Set Operations
-- IPP/1.1: Encoding and Transport
-- IPP/1.1: Implementers Guide
-- IPP/1.1: Model and Semantics
-- RFC 1179, Line
-Printer Daemon Protocol
-- RFC 2567, Design
-Goals for an Internet Printing Protocol
-- RFC 2568, Rationale
-for the Structure of the Model and Protocol for the Internet
-Printing Protocol
-- RFC 2569, Mapping
-between LPD and IPP Protocols
-- RFC 2616, Hypertext
-Transfer Protocol -- HTTP/1.1
-- RFC 2617, HTTP
-Authentication: Basic and Digest Access Authentication
+Adobe PostScript Language Reference, Third Edition.
+- IPP: Job and Printer Set Operations
+- IPP/1.1: Encoding and Transport
+- IPP/1.1: Implementers Guide
+- IPP/1.1: Model and Semantics
+- RFC 1179, Line Printer
+ Daemon Protocol
+- RFC 2567, Design Goals
+ for an Internet Printing Protocol
+- RFC 2568, Rationale
+ for the Structure of the Model and Protocol for the Internet
+ Printing Protocol
+- RFC 2569, Mapping
+ between LPD and IPP Protocols
+- RFC 2616, Hypertext
+ Transfer Protocol -- HTTP/1.1
+- RFC 2617, HTTP
+ Authentication: Basic and Digest Access Authentication
3 Additions
-CUPS 1.1 includes many new features from the 1.0.x releases.
+CUPS 1.1 includes many new features from the 1.0.x releases.
3.1 Filters
3.1.1 imagetoraster
, imagetops
-The image file filters have been upgraded to support conversion of
-Microsoft Bitmap ("BMP") and Alias PIX files.
+The image file filters have been upgraded to support conversion of
+ Microsoft Bitmap ("BMP") and Alias PIX files.
3.1.2 pdftops
-A new pdftops filter has been developed that is based on the
-excellent Xpdf 0.90 software from Derek B. Noonburg. The new filter is
-faster, smaller, and considerably more reliable than the
-Ghostscript-based filter in CUPS 1.0.
+A new pdftops filter has been developed that is based on the
+ excellent Xpdf 0.90 software from Derek B. Noonburg. The new filter is
+ faster, smaller, and considerably more reliable than the
+ Ghostscript-based filter in CUPS 1.0.
3.1.3 pstoraster
-The pstoraster
filter has been integrated with GNU
-GhostScript 5.50. The new RIP supports most Level 3 PostScript language
-features.
+The pstoraster
filter has been integrated with GNU
+ GhostScript 5.50. The new RIP supports most Level 3 PostScript language
+ features.
3.1.4 rastertoepson
-The new rastertoepson
filter supports EPSON printers
-using the ESC/P or ESC/P2 command sets. PPDs are supplied for 9-pin,
-24-pin, Stylus Color, and Stylus Photo printers.
+The new rastertoepson
filter supports EPSON printers
+ using the ESC/P or ESC/P2 command sets. PPDs are supplied for 9-pin,
+ 24-pin, Stylus Color, and Stylus Photo printers.
3.2 User-Defined Printers and Options
-The new lpoptions
command allows users to configure
-default document options and create additional "instances" of existing
-printers, each with unique options.
+The new lpoptions
command allows users to configure
+ default document options and create additional "instances" of existing
+ printers, each with unique options.
The lp
, lpr
, and lpstat
- commands have been upgraded to use this option and printer instance
-information automatically.
+ commands have been upgraded to use this option and printer instance
+ information automatically.
3.3 Daemons
-CUPS 1.1 includes two new daemons that provide enhanced network
-printing support.
+CUPS 1.1 includes two new daemons that provide enhanced network
+ printing support.
3.3.1 cups-lpd
-The cups-lpd
daemon provides support for clients using
-the Line Printer Daemon protocol.
+The cups-lpd
daemon provides support for clients using
+ the Line Printer Daemon protocol.
3.3.2 cups-polld
-The cups-polld
daemon provides remote polling services
-for the scheduler.
+The cups-polld
daemon provides remote polling services
+ for the scheduler.
3.4 Commands
-CUPS 1.1 includes several new printing commands.
+CUPS 1.1 includes several new printing commands.
3.4.1 lpoptions
-The lpoptions
command provides user-defined printers
-and options.
+The lpoptions
command provides user-defined printers and
+ options.
3.4.2 lpmove
-The lpmove
command moves a print job to a new
-destination.
+The lpmove
command moves a print job to a new
+ destination.
3.4.3 lpinfo
-The lpinfo
command lists the available PPD files or
-devices.
+The lpinfo
command lists the available PPD files or
+ devices.
3.5 IPP Implementation
CUPS 1.1 adds support for the set-job-attributes
- extension operation as well as two new CUPS-specific extension
-operations to determine which devices and printer drivers are available
-on the system.
-Further information on the CUPS implementation of IPP can be found
-in CUPS-IPP-1.1.
+ extension operation as well as two new CUPS-specific extension
+ operations to determine which devices and printer drivers are available
+ on the system.
+Further information on the CUPS implementation of IPP can be found in
+ CUPS-IPP-1.1.
4 Changes
-CUPS 1.1 includes many changes from the 1.0.x releases.
+CUPS 1.1 includes many changes from the 1.0.x releases.
4.1 Directory Structure
-The directory structure in CUPS 1.1 has been modified to conform to
-the Filesystem Hierarchy Standard, 2.0. The following table describes
-the new file locations.
+
The directory structure in CUPS 1.1 has been modified to conform to
+ the Filesystem Hierarchy Standard, 2.0. The following table describes
+ the new file locations.
- Table 1: Directory structure
-changes from CUPS 1.0.x to 1.1.x.
+ Table 1: Directory structure changes
+ from CUPS 1.0.x to 1.1.x.
Description CUPS 1.0.x CUPS 1.1.x
Backends /var/cups/backend /usr/lib/cups/backend
@@ -231,67 +231,66 @@ changes from CUPS 1.0.x to 1.1.x.
4.2 IPP Implementation
-CUPS 1.1 is based on version 1.1 of the Internet Printing Protocol.
+CUPS 1.1 is based on version 1.1 of the Internet Printing Protocol.
The new scheduler supports the create-job
and
send-document
operations. In addition, the job-sheets
, job-sheets-default
, and job-sheets-supported
- attributes are now supported for banner pages.
+ attributes are now supported for banner pages.
The CUPS-get-printers
and CUPS-get-classes
- operations have been upgraded to support limited filtering based upon
-the printer-type
, printer-location
,
-printer-info
, and printer-make-and-model
- attributes.
+ operations have been upgraded to support limited filtering based upon
+ the printer-type
, printer-location
,
+printer-info
, and printer-make-and-model
attributes.
The CUPS-add-printer
operation now supports the
-ppd-name
attribute to specify a locally-available PPD file
-rather than sending the PPD file from the client with the request.
-Further information on the CUPS implementation of IPP can be found
-in CUPS-IPP-1.1.
+ppd-name attribute to specify a locally-available PPD file rather
+ than sending the PPD file from the client with the request.
+Further information on the CUPS implementation of IPP can be found in
+ CUPS-IPP-1.1.
A Glossary
A.1 Terms
-- C
-- A computer language.
-- parallel
-- Sending or receiving data more than 1 bit at a time.
-- pipe
-- A one-way communications channel between two programs.
-- serial
-- Sending or receiving data 1 bit at a time.
-- socket
-- A two-way network communications channel.
+- C
+- A computer language.
+- parallel
+- Sending or receiving data more than 1 bit at a time.
+- pipe
+- A one-way communications channel between two programs.
+- serial
+- Sending or receiving data 1 bit at a time.
+- socket
+- A two-way network communications channel.
A.2 Acronyms
-- ASCII
-- American Standard Code for Information Interchange
-- CUPS
-- Common UNIX Printing System
-- ESC/P
-- EPSON Standard Code for Printers
-- FTP
-- File Transfer Protocol
-- HP-GL
-- Hewlett-Packard Graphics Language
-- HP-PCL
-- Hewlett-Packard Page Control Language
-- HP-PJL
-- Hewlett-Packard Printer Job Language
-- IETF
-- Internet Engineering Task Force
-- IPP
-- Internet Printing Protocol
-- ISO
-- International Standards Organization
-- LPD
-- Line Printer Daemon
-- MIME
-- Multimedia Internet Mail Exchange
-- PPD
-- PostScript Printer Description
-- SMB
-- Server Message Block
-- TFTP
-- Trivial File Transfer Protocol
+- ASCII
+- American Standard Code for Information Interchange
+- CUPS
+- Common UNIX Printing System
+- ESC/P
+- EPSON Standard Code for Printers
+- FTP
+- File Transfer Protocol
+- HP-GL
+- Hewlett-Packard Graphics Language
+- HP-PCL
+- Hewlett-Packard Page Control Language
+- HP-PJL
+- Hewlett-Packard Printer Job Language
+- IETF
+- Internet Engineering Task Force
+- IPP
+- Internet Printing Protocol
+- ISO
+- International Standards Organization
+- LPD
+- Line Printer Daemon
+- MIME
+- Multimedia Internet Mail Exchange
+- PPD
+- PostScript Printer Description
+- SMB
+- Server Message Block
+- TFTP
+- Trivial File Transfer Protocol
diff --git a/doc/svd.pdf b/doc/svd.pdf
index 05918d142a..b0d4a71a66 100644
Binary files a/doc/svd.pdf and b/doc/svd.pdf differ
diff --git a/filter/Makefile b/filter/Makefile
index fdc02bdd94..1a209fe141 100644
--- a/filter/Makefile
+++ b/filter/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.41 2001/02/02 16:37:44 mike Exp $"
+# "$Id: Makefile,v 1.41.2.1 2001/12/26 16:52:38 mike Exp $"
#
# Filter makefile for the Common UNIX Printing System (CUPS).
#
@@ -25,7 +25,7 @@
include ../Makedefs
TARGETS = hpgltops texttops pstops imagetops imagetoraster \
- rastertoepson rastertohp
+ rastertodymo rastertoepson rastertohp
HPGLOBJS = hpgl-attr.o hpgl-config.o hpgl-main.o hpgl-prolog.o \
hpgl-char.o hpgl-input.o hpgl-polygon.o hpgl-vector.o
@@ -36,8 +36,8 @@ IMAGEOBJS = image-bmp.o image-colorspace.o image-gif.o image-jpeg.o \
FORMOBJS = form-attr.o form-main.o form-ps.o form-text.o form-tree.o
OBJS = $(HPGLOBJS) $(IMAGEOBJS) $(FORMOBJS) \
imagetops.o imagetoraster.o common.o pstops.o raster.o \
- rastertoepson.o rastertohp.o texttops.o textcommon.o
-
+ rastertodymo.o rastertoepson.o rastertohp.o texttops.o \
+ textcommon.o
#
# Make all targets...
@@ -59,20 +59,21 @@ clean:
#
install:
- -$(MKDIR) $(LIBDIR)
- $(CHMOD) ugo+rx $(LIBDIR)
+ $(INSTALL_DIR) $(SERVERBIN)/filter
+ for file in $(TARGETS); do \
+ $(INSTALL_BIN) $$file $(SERVERBIN)/filter; \
+ done
+ $(INSTALL_DIR) $(LIBDIR)
$(INSTALL_LIB) $(LIBCUPSIMAGE) $(LIBDIR)
- -if test $(LIBCUPSIMAGE) != "libcupsimage.a" -a $(LIBCUPSIMAGE) != "libcupsimage.la"; then \
+ -if test $(LIBCUPSIMAGE) = "libcupsimage.so.2" -o $(LIBCUPSIMAGE) = "libcupsimage.sl.2"; then \
$(RM) $(LIBDIR)/`basename $(LIBCUPSIMAGE) .2`; \
$(LN) $(LIBCUPSIMAGE) $(LIBDIR)/`basename $(LIBCUPSIMAGE) .2`; \
fi
- -$(MKDIR) $(SERVERBIN)/filter
- $(CHMOD) ugo+rx $(SERVERBIN)
- $(CHMOD) ugo+rx $(SERVERBIN)/filter
- $(INSTALL_BIN) $(TARGETS) $(SERVERBIN)/filter
- -$(MKDIR) $(INCLUDEDIR)/cups
- $(CHMOD) ugo+rx $(INCLUDEDIR)
- $(CHMOD) ugo+rx $(INCLUDEDIR)/cups
+ -if test $(LIBCUPSIMAGE) = "libcupsimage.2.dylib"; then \
+ $(RM) $(LIBDIR)/libcupsimage.dylib; \
+ $(LN) $(LIBCUPSIMAGE) $(LIBDIR)/libcupsimage.dylib; \
+ fi
+ $(INSTALL_DIR) $(INCLUDEDIR)/cups
$(INSTALL_DATA) raster.h $(INCLUDEDIR)/cups
@@ -107,14 +108,37 @@ libcupsimage.so.2 libcupsimage.sl.2: $(IMAGEOBJS) ../Makedefs
$(LN) $@ `basename $@ .2`
+#
+# libcupsimage.2.dylib
+#
+
+libcupsimage.2.dylib: $(IMAGEOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o $@ $(IMAGEOBJS) $(DSOLIBS) $(LINKCUPS) -lm -lcc_dynamic
+ $(RM) libcupsimage.dylib
+ $(LN) $@ libcupsimage.dylib
+
+
+#
+# libcupsimage_s.a
+#
+
+libcupsimage_s.a: $(IMAGEOBJS) ../Makedefs
+ echo Linking $@...
+ $(DSO) $(DSOFLAGS) -o libcupsimage_s.o $(IMAGEOBJS) $(DSOLIBS) \
+ $(LINKCUPS) -lm
+ $(RM) $@
+ $(AR) $(ARFLAGS) $@ libcupsimage_s.o
+
+
#
# libcupsimage.la
#
libcupsimage.la: $(IMAGEOBJS) ../Makedefs
echo Linking $@...
- $(CC) -o $@ $(IMAGEOBJS:.o=.lo) -rpath $(LIBDIR) \
- -version-info 2:0
+ $(DSO) -o $(DSOFLAGS) $@ $(IMAGEOBJS:.o=.lo) $(DSOLIBS) \
+ -rpath $(LIBDIR) -version-info 2:0
#
@@ -165,6 +189,16 @@ pstops: pstops.o common.o ../Makedefs ../cups/$(LIBCUPS)
pstops.o: common.h
+#
+# rastertodymo
+#
+
+rastertodymo: rastertodymo.o ../Makedefs ../cups/$(LIBCUPS) libcupsimage.a
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o $@ rastertodymo.o libcupsimage.a $(LIBS)
+rastertodymo.o: raster.h
+
+
#
# rastertoepson
#
@@ -203,5 +237,5 @@ $(OBJS): ../Makedefs ../cups/cups.h ../cups/ppd.h ../cups/language.h
#
-# End of "$Id: Makefile,v 1.41 2001/02/02 16:37:44 mike Exp $".
+# End of "$Id: Makefile,v 1.41.2.1 2001/12/26 16:52:38 mike Exp $".
#
diff --git a/filter/image-colorspace.c b/filter/image-colorspace.c
index 3781f22fe0..b4601317d2 100644
--- a/filter/image-colorspace.c
+++ b/filter/image-colorspace.c
@@ -1,5 +1,5 @@
/*
- * "$Id: image-colorspace.c,v 1.22 2001/03/29 14:58:52 mike Exp $"
+ * "$Id: image-colorspace.c,v 1.22.2.1 2001/12/26 16:52:38 mike Exp $"
*
* Colorspace conversions for the Common UNIX Printing System (CUPS).
*
@@ -23,6 +23,7 @@
*
* Contents:
*
+ * ImageSetProfile() - Set the device color profile.
* ImageWhiteToWhite() - Convert luminance colors to device-dependent
* ImageWhiteToRGB() - Convert luminance data to RGB.
* ImageWhiteToBlack() - Convert luminance colors to black.
@@ -56,12 +57,13 @@
/*
- * Globals...
+ * Local globals...
*/
-extern int ImageHaveProfile;
-extern int ImageDensity[256];
-extern int ImageMatrix[3][3][256];
+static int ImageHaveProfile = 0; /* Do we have a color profile? */
+static int ImageDensity[256]; /* Ink/marker density LUT */
+static int ImageMatrix[3][3][256]; /* Color transform matrix LUT */
+
/*
* Local functions...
@@ -78,6 +80,31 @@ static void zrotate(float [3][3], float, float);
static void zshear(float [3][3], float, float);
+/*
+ * 'ImageSetProfile()' - Set the device color profile.
+ */
+
+void
+ImageSetProfile(float d, /* I - Ink/marker density */
+ float g, /* I - Ink/marker gamma */
+ float matrix[3][3]) /* I - Color transform matrix */
+{
+ int i, j, k; /* Looping vars */
+ float m; /* Current matrix value */
+ int *im; /* Pointer into ImageMatrix */
+
+ ImageHaveProfile = 1;
+
+ for (i = 0, im = ImageMatrix[0][0]; i < 3; i ++)
+ for (j = 0; j < 3; j ++)
+ for (k = 0, m = matrix[i][j]; k < 256; k ++)
+ *im++ = (int)(k * m + 0.5);
+
+ for (k = 0, im = ImageDensity; k < 256; k ++)
+ *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5;
+}
+
+
/*
* 'ImageWhiteToWhite()' - Convert luminance colors to device-dependent
* luminance.
@@ -878,5 +905,5 @@ zshear(float mat[3][3], /* I - Matrix */
/*
- * End of "$Id: image-colorspace.c,v 1.22 2001/03/29 14:58:52 mike Exp $".
+ * End of "$Id: image-colorspace.c,v 1.22.2.1 2001/12/26 16:52:38 mike Exp $".
*/
diff --git a/filter/image-jpeg.c b/filter/image-jpeg.c
index 6bf640c7c5..f6a517115e 100644
--- a/filter/image-jpeg.c
+++ b/filter/image-jpeg.c
@@ -1,5 +1,5 @@
/*
- * "$Id: image-jpeg.c,v 1.11 2001/01/22 15:03:38 mike Exp $"
+ * "$Id: image-jpeg.c,v 1.11.2.1 2001/12/26 16:52:38 mike Exp $"
*
* JPEG image routines for the Common UNIX Printing System (CUPS).
*
@@ -98,7 +98,7 @@ ImageReadJPEG(image_t *img, /* IO - Image */
}
fprintf(stderr, "DEBUG: JPEG image %dx%dx%d, %dx%d PPI\n",
- img->xsize, img->colorspace, cinfo.output_components,
+ img->xsize, img->ysize, cinfo.output_components,
img->xppi, img->yppi);
ImageSetMaxTiles(img, 0);
@@ -190,5 +190,5 @@ ImageReadJPEG(image_t *img, /* IO - Image */
/*
- * End of "$Id: image-jpeg.c,v 1.11 2001/01/22 15:03:38 mike Exp $".
+ * End of "$Id: image-jpeg.c,v 1.11.2.1 2001/12/26 16:52:38 mike Exp $".
*/
diff --git a/filter/image.c b/filter/image.c
index db1d827fd8..ee14f77d5b 100644
--- a/filter/image.c
+++ b/filter/image.c
@@ -1,5 +1,5 @@
/*
- * "$Id: image.c,v 1.28 2001/03/01 22:51:30 mike Exp $"
+ * "$Id: image.c,v 1.28.2.1 2001/12/26 16:52:38 mike Exp $"
*
* Base image support for the Common UNIX Printing System (CUPS).
*
@@ -26,7 +26,6 @@
* ImageOpen() - Open an image file and read it into memory.
* ImageClose() - Close an image file.
* ImageSetMaxTiles() - Set the maximum number of tiles to cache.
- * ImageSetProfile() - Set the device color profile.
* ImageGetCol() - Get a column of pixels from an image.
* ImageGetRow() - Get a row of pixels from an image.
* ImagePutCol() - Put a column of pixels to an image.
@@ -46,15 +45,6 @@
#include
-/*
- * Globals...
- */
-
-int ImageHaveProfile = 0; /* Do we have a color profile? */
-int ImageDensity[256]; /* Ink/marker density LUT */
-int ImageMatrix[3][3][256]; /* Color transform matrix LUT */
-
-
/*
* Local functions...
*/
@@ -311,31 +301,6 @@ ImageSetMaxTiles(image_t *img, /* I - Image to set */
}
-/*
- * 'ImageSetProfile()' - Set the device color profile.
- */
-
-void
-ImageSetProfile(float d, /* I - Ink/marker density */
- float g, /* I - Ink/marker gamma */
- float matrix[3][3]) /* I - Color transform matrix */
-{
- int i, j, k; /* Looping vars */
- float m; /* Current matrix value */
- int *im; /* Pointer into ImageMatrix */
-
- ImageHaveProfile = 1;
-
- for (i = 0, im = ImageMatrix[0][0]; i < 3; i ++)
- for (j = 0; j < 3; j ++)
- for (k = 0, m = matrix[i][j]; k < 256; k ++)
- *im++ = (int)(k * m + 0.5);
-
- for (k = 0, im = ImageDensity; k < 256; k ++)
- *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5;
-}
-
-
/*
* 'ImageGetCol()' - Get a column of pixels from an image.
*/
@@ -804,5 +769,5 @@ flush_tile(image_t *img) /* I - Image */
/*
- * End of "$Id: image.c,v 1.28 2001/03/01 22:51:30 mike Exp $".
+ * End of "$Id: image.c,v 1.28.2.1 2001/12/26 16:52:38 mike Exp $".
*/
diff --git a/filter/imagetops.c b/filter/imagetops.c
index ac1db10baf..f494cd4adf 100644
--- a/filter/imagetops.c
+++ b/filter/imagetops.c
@@ -1,5 +1,5 @@
/*
- * "$Id: imagetops.c,v 1.36.2.1 2001/05/13 18:38:18 mike Exp $"
+ * "$Id: imagetops.c,v 1.36.2.2 2001/12/26 16:52:39 mike Exp $"
*
* Image file to PostScript filter for the Common UNIX Printing System (CUPS).
*
@@ -305,6 +305,12 @@ main(int argc, /* I - Number of command-line arguments */
xinches = (float)img->xsize / (float)xppi;
yinches = (float)img->ysize / (float)yppi;
+ if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
+ {
+ xinches = xinches * atoi(val) / 100;
+ yinches = yinches * atoi(val) / 100;
+ }
+
if (cupsGetOption("orientation", num_options, options) == NULL &&
cupsGetOption("landscape", num_options, options) == NULL)
{
@@ -859,5 +865,5 @@ ps_ascii85(ib_t *data, /* I - Data to print */
/*
- * End of "$Id: imagetops.c,v 1.36.2.1 2001/05/13 18:38:18 mike Exp $".
+ * End of "$Id: imagetops.c,v 1.36.2.2 2001/12/26 16:52:39 mike Exp $".
*/
diff --git a/filter/imagetoraster.c b/filter/imagetoraster.c
index 22c457f439..229f7a0a87 100644
--- a/filter/imagetoraster.c
+++ b/filter/imagetoraster.c
@@ -1,5 +1,5 @@
/*
- * "$Id: imagetoraster.c,v 1.56.2.1 2001/05/13 18:38:19 mike Exp $"
+ * "$Id: imagetoraster.c,v 1.56.2.2 2001/12/26 16:52:39 mike Exp $"
*
* Image file to raster filter for the Common UNIX Printing System (CUPS).
*
@@ -677,6 +677,12 @@ main(int argc, /* I - Number of command-line arguments */
xinches = (float)img->xsize / (float)xppi;
yinches = (float)img->ysize / (float)yppi;
+ if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
+ {
+ xinches = xinches * atoi(val) / 100;
+ yinches = yinches * atoi(val) / 100;
+ }
+
if (cupsGetOption("orientation", num_options, options) == NULL &&
cupsGetOption("landscape", num_options, options) == NULL)
{
@@ -4442,5 +4448,5 @@ make_lut(ib_t *lut, /* I - Lookup table */
/*
- * End of "$Id: imagetoraster.c,v 1.56.2.1 2001/05/13 18:38:19 mike Exp $".
+ * End of "$Id: imagetoraster.c,v 1.56.2.2 2001/12/26 16:52:39 mike Exp $".
*/
diff --git a/filter/pstops.c b/filter/pstops.c
index bc4e585860..507004ab73 100644
--- a/filter/pstops.c
+++ b/filter/pstops.c
@@ -1,5 +1,5 @@
/*
- * "$Id: pstops.c,v 1.54.2.1 2001/05/13 18:38:20 mike Exp $"
+ * "$Id: pstops.c,v 1.54.2.2 2001/12/26 16:52:39 mike Exp $"
*
* PostScript filter for the Common UNIX Printing System (CUPS).
*
@@ -100,6 +100,7 @@ main(int argc, /* I - Number of command-line arguments */
int nbytes, /* Number of bytes read */
tbytes; /* Total bytes to read for binary data */
int page; /* Current page sequence number */
+ int real_page; /* "Real" page number in document */
int page_count; /* Page count for NUp */
int subpage; /* Sub-page number */
int copy; /* Current copy */
@@ -248,6 +249,12 @@ main(int argc, /* I - Number of command-line arguments */
return (1);
}
+ /*
+ * See if this is an EPS file...
+ */
+
+ UseESPsp = strstr(line, "EPS") != NULL;
+
/*
* Start sending the document with any commands needed...
*/
@@ -280,14 +287,15 @@ main(int argc, /* I - Number of command-line arguments */
*/
UseESPsp = 1;
+ }
- WriteLabelProlog(val);
+ WriteLabelProlog(val);
+ if (UseESPsp)
puts("userdict begin\n"
"/ESPshowpage /showpage load def\n"
"/showpage { } def\n"
"end");
- }
if (Copies > 1 && (!Collate || !slowcollate))
{
@@ -345,7 +353,7 @@ main(int argc, /* I - Number of command-line arguments */
* Then read all of the pages, filtering as needed...
*/
- for (page = 1;;)
+ for (page = 1, real_page = 1;;)
{
if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */
@@ -362,7 +370,7 @@ main(int argc, /* I - Number of command-line arguments */
}
else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
{
- if (!check_range(NumPages + 1))
+ if (!check_range(real_page))
{
while (psgets(line, sizeof(line), fp) != NULL)
if (strncmp(line, "%%BeginDocument:", 16) == 0 ||
@@ -371,7 +379,10 @@ main(int argc, /* I - Number of command-line arguments */
else if (strcmp(line, "%%EndDocument") == 0 && level > 0)
level --;
else if (strncmp(line, "%%Page:", 7) == 0 && level == 0)
+ {
+ real_page ++;
break;
+ }
continue;
}
@@ -398,6 +409,7 @@ main(int argc, /* I - Number of command-line arguments */
}
NumPages ++;
+ real_page ++;
}
else if (strncmp(line, "%%BeginBinary:", 14) == 0 ||
(strncmp(line, "%%BeginData:", 12) == 0 &&
@@ -963,5 +975,5 @@ start_nup(int number) /* I - Page number */
/*
- * End of "$Id: pstops.c,v 1.54.2.1 2001/05/13 18:38:20 mike Exp $".
+ * End of "$Id: pstops.c,v 1.54.2.2 2001/12/26 16:52:39 mike Exp $".
*/
diff --git a/filter/rastertodymo.c b/filter/rastertodymo.c
index 0518f76867..3ccebd45e6 100644
--- a/filter/rastertodymo.c
+++ b/filter/rastertodymo.c
@@ -1,5 +1,5 @@
/*
- * "$Id: rastertodymo.c,v 1.4 2001/07/18 20:45:51 mike Exp $"
+ * "$Id: rastertodymo.c,v 1.4.2.1 2001/12/26 16:52:40 mike Exp $"
*
* DYMO label printer filter for the Common UNIX Printing System (CUPS).
*
@@ -357,5 +357,5 @@ main(int argc, /* I - Number of command-line arguments */
/*
- * End of "$Id: rastertodymo.c,v 1.4 2001/07/18 20:45:51 mike Exp $".
+ * End of "$Id: rastertodymo.c,v 1.4.2.1 2001/12/26 16:52:40 mike Exp $".
*/
diff --git a/filter/textcommon.c b/filter/textcommon.c
index 0700d211b6..a28dd5cf0c 100644
--- a/filter/textcommon.c
+++ b/filter/textcommon.c
@@ -1,5 +1,5 @@
/*
- * "$Id: textcommon.c,v 1.16.2.1 2001/05/13 18:38:21 mike Exp $"
+ * "$Id: textcommon.c,v 1.16.2.2 2001/12/26 16:52:40 mike Exp $"
*
* Common text filter routines for the Common UNIX Printing System (CUPS).
*
@@ -970,10 +970,19 @@ TextMain(const char *name, /* I - Name of filter */
if (PrettyPrint)
Page[line][i].attr = attr;
+ else if (ch == ' ' && Page[line][i].ch)
+ ch = Page[line][i].ch;
else if (ch == Page[line][i].ch)
Page[line][i].attr |= ATTR_BOLD;
else if (Page[line][i].ch == '_')
Page[line][i].attr |= ATTR_UNDERLINE;
+ else if (ch == '_')
+ {
+ Page[line][i].attr |= ATTR_UNDERLINE;
+
+ if (Page[line][i].ch)
+ ch = Page[line][i].ch;
+ }
else
Page[line][i].attr = attr;
@@ -1142,5 +1151,5 @@ getutf8(FILE *fp) /* I - File to read from */
/*
- * End of "$Id: textcommon.c,v 1.16.2.1 2001/05/13 18:38:21 mike Exp $".
+ * End of "$Id: textcommon.c,v 1.16.2.2 2001/12/26 16:52:40 mike Exp $".
*/
diff --git a/fonts/Makefile b/fonts/Makefile
index 06ebc57e25..81d3289efa 100644
--- a/fonts/Makefile
+++ b/fonts/Makefile
@@ -64,10 +64,10 @@ clean:
#
install:
- -$(MKDIR) $(DATADIR)/fonts
- $(CHMOD) ugo+rx $(DATADIR)
- $(CHMOD) ugo+rx $(DATADIR)/fonts
- $(INSTALL_DATA) $(FONTS) $(DATADIR)/fonts
+ $(INSTALL_DIR) $(DATADIR)/fonts
+ for file in $(FONTS); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/fonts; \
+ done
#
diff --git a/locale/Makefile b/locale/Makefile
index 3703403d56..e3edc2d642 100644
--- a/locale/Makefile
+++ b/locale/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.8 2000/07/07 17:02:44 mike Exp $"
+# "$Id: Makefile,v 1.8.2.1 2001/12/26 16:52:40 mike Exp $"
#
# Locale file makefile for the Common UNIX Printing System (CUPS).
#
@@ -28,7 +28,7 @@ include ../Makedefs
# Locales...
#
-LOCALES = C de en es fr it
+LOCALES = C cs de en es fr it
#
@@ -50,13 +50,9 @@ clean:
#
install:
- -$(MKDIR) $(LOCALEDIR)
- $(CHMOD) ugo+rx $(LOCALEDIR)
+ $(INSTALL_DIR) $(LOCALEDIR)
for dir in $(LOCALES) ; do \
- if test ! -d $(LOCALEDIR)/$$dir ; then \
- $(MKDIR) $(LOCALEDIR)/$$dir ; \
- $(CHMOD) ugo+rx $(LOCALEDIR)/$$dir ; \
- fi ; \
+ $(INSTALL_DIR) $(LOCALEDIR)/$$dir ; \
$(INSTALL_DATA) $$dir/cups_$$dir $(LOCALEDIR)/$$dir ; \
done
@@ -76,5 +72,5 @@ translate.o: ../cups/http.h
#
-# End of "$Id: Makefile,v 1.8 2000/07/07 17:02:44 mike Exp $".
+# End of "$Id: Makefile,v 1.8.2.1 2001/12/26 16:52:40 mike Exp $".
#
diff --git a/man/Makefile b/man/Makefile
index 9396282f22..96af00b99b 100644
--- a/man/Makefile
+++ b/man/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.12 2001/02/20 17:33:00 mike Exp $"
+# "$Id: Makefile,v 1.12.2.1 2001/12/26 16:52:41 mike Exp $"
#
# Man page makefile for the Common UNIX Printing System (CUPS).
#
@@ -28,23 +28,26 @@ include ../Makedefs
# Man pages...
#
-MAN1 = backend.man filter.man lp.man lpoptions.man lpq.man lprm.man \
- lpr.man lpstat.man
+MAN1 = backend.man filter.man lp.man lpoptions.man lppasswd.man \
+ lpq.man lprm.man lpr.man lpstat.man
+MAN3 = cups-config.man
MAN5 = classes.conf.man cupsd.conf.man mime.convs.man mime.types.man \
printers.conf.man
-MAN8 = accept.man cups-lpd.man cups-polld.man cupsd.man enable.man \
- lpadmin.man lpinfo.man lpmove.man lpc.man
+MAN8 = accept.man cupsaddsmb.man cups-lpd.man cups-polld.man \
+ cupsd.man enable.man lpadmin.man lpinfo.man lpmove.man \
+ lpc.man
CAT1 = $(MAN1:.man=.$(CAT1EXT))
-CAT5 = $(MAN5:.man=.$(CAT1EXT))
-CAT8 = $(MAN8:.man=.$(CAT1EXT))
+CAT3 = $(MAN3:.man=.$(CAT3EXT))
+CAT5 = $(MAN5:.man=.$(CAT5EXT))
+CAT8 = $(MAN8:.man=.$(CAT8EXT))
#
# Make everything...
#
-all: $(CAT1) $(CAT5) $(CAT8)
+all: $(CAT1) $(CAT3) $(CAT5) $(CAT8)
#
@@ -52,7 +55,7 @@ all: $(CAT1) $(CAT5) $(CAT8)
#
clean:
- $(RM) $(CAT1) $(CAT5) $(CAT8)
+ $(RM) $(CAT1) $(CAT3) $(CAT5) $(CAT8)
#
@@ -60,21 +63,21 @@ clean:
#
install:
- -$(MKDIR) $(MANDIR)/man1
- -$(CHMOD) ugo+rx $(MANDIR)
- -$(CHMOD) ugo+rx $(MANDIR)/man1
+ $(INSTALL_DIR) $(MANDIR)/man1
for file in $(MAN1); do \
$(INSTALL_MAN) $$file $(MANDIR)/man1/`basename $$file man`1; \
done
$(RM) $(MANDIR)/man1/cancel.1
$(LN) lp.1 $(MANDIR)/man1/cancel.1
- -$(MKDIR) $(MANDIR)/man5
- -$(CHMOD) ugo+rx $(MANDIR)/man5
+ $(INSTALL_DIR) $(PMANDIR)/man3
+ for file in $(MAN3); do \
+ $(INSTALL_MAN) $$file $(PMANDIR)/man3/`basename $$file man`3; \
+ done
+ $(INSTALL_DIR) $(MANDIR)/man5
for file in $(MAN5); do \
$(INSTALL_MAN) $$file $(MANDIR)/man5/`basename $$file man`5; \
done
- -$(MKDIR) $(AMANDIR)/man$(MAN8EXT)
- -$(CHMOD) ugo+rx $(AMANDIR)/man$(MAN8EXT)
+ $(INSTALL_DIR) $(AMANDIR)/man$(MAN8EXT)
for file in $(MAN8); do \
$(INSTALL_MAN) $$file $(AMANDIR)/man$(MAN8EXT)/`basename $$file man`$(MAN8EXT); \
done
@@ -82,23 +85,30 @@ install:
$(LN) accept.$(MAN8EXT) $(AMANDIR)/man$(MAN8EXT)/reject.$(MAN8EXT)
$(RM) $(AMANDIR)/man$(MAN8EXT)/disable.$(MAN8EXT)
$(LN) enable.$(MAN8EXT) $(AMANDIR)/man$(MAN8EXT)/disable.$(MAN8EXT)
- -$(MKDIR) $(MANDIR)/cat1
- -$(CHMOD) ugo+rx $(MANDIR)/cat1
- $(INSTALL_MAN) $(CAT1) $(MANDIR)/cat1
+ $(INSTALL_DIR) $(MANDIR)/cat1
+ for file in $(CAT1); do \
+ $(INSTALL_MAN) $$file $(MANDIR)/cat1; \
+ done
$(RM) $(MANDIR)/cat1/cancel.$(CAT1EXT)
$(LN) lp.$(CAT1EXT) $(MANDIR)/cat1/cancel.$(CAT1EXT)
- -$(MKDIR) $(MANDIR)/cat5
- -$(CHMOD) ugo+rx $(MANDIR)/cat5
- $(INSTALL_MAN) $(CAT5) $(MANDIR)/cat5
- -$(MKDIR) $(AMANDIR)/cat$(MAN8EXT)
- -$(CHMOD) ugo+rx $(AMANDIR)/cat$(MAN8EXT)
- $(INSTALL_MAN) $(CAT8) $(AMANDIR)/cat$(MAN8EXT)
+ $(INSTALL_DIR) $(PMANDIR)/cat3
+ for file in $(CAT3); do \
+ $(INSTALL_MAN) $$file $(PMANDIR)/cat3; \
+ done
+ $(INSTALL_DIR) $(MANDIR)/cat5
+ for file in $(CAT5); do \
+ $(INSTALL_MAN) $$file $(MANDIR)/cat5; \
+ done
+ $(INSTALL_DIR) $(AMANDIR)/cat$(MAN8EXT)
+ for file in $(CAT8); do \
+ $(INSTALL_MAN) $$file $(AMANDIR)/cat$(MAN8EXT); \
+ done
$(RM) $(AMANDIR)/cat$(MAN8EXT)/reject.$(CAT8EXT)
- $(LN) accept.$(CAT1EXT) $(AMANDIR)/cat$(MAN8EXT)/reject.$(CAT8EXT)
+ $(LN) accept.$(CAT8EXT) $(AMANDIR)/cat$(MAN8EXT)/reject.$(CAT8EXT)
$(RM) $(AMANDIR)/cat$(MAN8EXT)/disable.$(CAT8EXT)
- $(LN) enable.$(CAT1EXT) $(AMANDIR)/cat$(MAN8EXT)/disable.$(CAT8EXT)
+ $(LN) enable.$(CAT8EXT) $(AMANDIR)/cat$(MAN8EXT)/disable.$(CAT8EXT)
#
-# End of "$Id: Makefile,v 1.12 2001/02/20 17:33:00 mike Exp $".
+# End of "$Id: Makefile,v 1.12.2.1 2001/12/26 16:52:41 mike Exp $".
#
diff --git a/man/cups-config.man b/man/cups-config.man
index e681adaae8..e4cad76cea 100644
--- a/man/cups-config.man
+++ b/man/cups-config.man
@@ -1,5 +1,5 @@
.\"
-.\" "$Id: cups-config.man,v 1.1 2001/10/26 03:16:48 mike Exp $"
+.\" "$Id: cups-config.man,v 1.1.2.1 2001/12/26 16:52:41 mike Exp $"
.\"
.\" cups-config man page for the Common UNIX Printing System (CUPS).
.\"
@@ -91,5 +91,5 @@ http://localhost:631/documentation.html
.SH COPYRIGHT
Copyright 1993-2001 by Easy Software Products, All Rights Reserved.
.\"
-.\" End of "$Id: cups-config.man,v 1.1 2001/10/26 03:16:48 mike Exp $".
+.\" End of "$Id: cups-config.man,v 1.1.2.1 2001/12/26 16:52:41 mike Exp $".
.\"
diff --git a/man/cupsaddsmb.man b/man/cupsaddsmb.man
index 4d7da8879b..a6fcab69f3 100644
--- a/man/cupsaddsmb.man
+++ b/man/cupsaddsmb.man
@@ -1,5 +1,5 @@
.\"
-.\" "$Id: cupsaddsmb.man,v 1.2 2001/11/09 17:19:41 mike Exp $"
+.\" "$Id: cupsaddsmb.man,v 1.2.2.1 2001/12/26 16:52:41 mike Exp $"
.\"
.\" cupsaddsmb man page for the Common UNIX Printing System (CUPS).
.\"
@@ -110,5 +110,5 @@ http://localhost:631/documentation.html
.SH COPYRIGHT
Copyright 1993-2001 by Easy Software Products, All Rights Reserved.
.\"
-.\" End of "$Id: cupsaddsmb.man,v 1.2 2001/11/09 17:19:41 mike Exp $".
+.\" End of "$Id: cupsaddsmb.man,v 1.2.2.1 2001/12/26 16:52:41 mike Exp $".
.\"
diff --git a/man/lp.man b/man/lp.man
index edfd8c6d90..a76adcc1c8 100644
--- a/man/lp.man
+++ b/man/lp.man
@@ -1,5 +1,5 @@
.\"
-.\" "$Id: lp.man,v 1.6 2001/03/09 14:26:54 mike Exp $"
+.\" "$Id: lp.man,v 1.6.2.1 2001/12/26 16:52:41 mike Exp $"
.\"
.\" lp/cancel man page for the Common UNIX Printing System (CUPS).
.\"
@@ -21,7 +21,7 @@
.\" EMail: cups-info@cups.org
.\" WWW: http://www.cups.org
.\"
-.TH lp 1 "Common UNIX Printing System" "23 January 2001" "Easy Software Products"
+.TH lp 1 "Common UNIX Printing System" "25 September 2001" "Easy Software Products"
.SH NAME
lp \- print files
.br
@@ -36,7 +36,7 @@ cancel \- cancel jobs
.I num-copies
[ \-o
.I option
-] [ \-p/q
+] [ \-q
.I priority
] [ \-s ] [ \-t
.I title
@@ -57,7 +57,7 @@ cancel \- cancel jobs
.I num-copies
[ \-o
.I option
-] [ \-p/q
+] [ \-q
.I priority
] [ \-t
.I title
@@ -114,10 +114,10 @@ Sets the number of copies to print from 1 to 100.
.br
Sets a job option.
.TP 5
-\-p/q \fIpriority\fR
+\-q \fIpriority\fR
.br
-Sets the job priority from 1 (lowest) to 100 (highest). The default priority
-is 50.
+Sets the job priority from 1 (lowest) to 100 (highest). The
+default priority is 50.
.TP 5
\-s
.br
@@ -145,6 +145,10 @@ any printable character except SPACE and TAB. Also, printer and class names are
\fBnot\fR case-sensitive.
.LP
The "m" option is not functional in CUPS 1.1.
+.LP
+The "q" option accepts a different range of values than the
+Solaris lp command, matching the IPP job priority values (1-100)
+instead of the Solaris values (0-39).
.SH SEE ALSO
lpstat(1),
CUPS Software Users Manual,
@@ -152,5 +156,5 @@ http://localhost:631/documentation.html
.SH COPYRIGHT
Copyright 1993-2001 by Easy Software Products, All Rights Reserved.
.\"
-.\" End of "$Id: lp.man,v 1.6 2001/03/09 14:26:54 mike Exp $".
+.\" End of "$Id: lp.man,v 1.6.2.1 2001/12/26 16:52:41 mike Exp $".
.\"
diff --git a/pdftops/Array.cxx b/pdftops/Array.cxx
index 9681b6854c..141afc8cab 100644
--- a/pdftops/Array.cxx
+++ b/pdftops/Array.cxx
@@ -19,7 +19,8 @@
// Array
//------------------------------------------------------------------------
-Array::Array() {
+Array::Array(XRef *xrefA) {
+ xref = xrefA;
elems = NULL;
size = length = 0;
ref = 1;
@@ -43,7 +44,7 @@ void Array::add(Object *elem) {
}
Object *Array::get(int i, Object *obj) {
- return elems[i].fetch(obj);
+ return elems[i].fetch(xref, obj);
}
Object *Array::getNF(int i, Object *obj) {
diff --git a/pdftops/Array.h b/pdftops/Array.h
index ecf2eea6fd..1616fc33f4 100644
--- a/pdftops/Array.h
+++ b/pdftops/Array.h
@@ -15,6 +15,8 @@
#include "Object.h"
+class XRef;
+
//------------------------------------------------------------------------
// Array
//------------------------------------------------------------------------
@@ -23,7 +25,7 @@ class Array {
public:
// Constructor.
- Array();
+ Array(XRef *xrefA);
// Destructor.
~Array();
@@ -44,6 +46,7 @@ public:
private:
+ XRef *xref; // the xref table for this PDF file
Object *elems; // array of elements
int size; // size of array
int length; // number of elements in array
diff --git a/pdftops/Catalog.cxx b/pdftops/Catalog.cxx
index 815cca3ae0..fadb4763b6 100644
--- a/pdftops/Catalog.cxx
+++ b/pdftops/Catalog.cxx
@@ -13,6 +13,7 @@
#include
#include "gmem.h"
#include "Object.h"
+#include "XRef.h"
#include "Array.h"
#include "Dict.h"
#include "Page.h"
@@ -24,24 +25,27 @@
// Catalog
//------------------------------------------------------------------------
-Catalog::Catalog(Object *catDict) {
- Object pagesDict;
+Catalog::Catalog(XRef *xrefA, GBool printCommands) {
+ Object catDict, pagesDict;
Object obj, obj2;
int numPages0;
int i;
ok = gTrue;
+ xref = xrefA;
pages = NULL;
pageRefs = NULL;
numPages = pagesSize = 0;
+ baseURI = NULL;
- if (!catDict->isDict()) {
- error(-1, "Catalog object is wrong type (%s)", catDict->getTypeName());
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
goto err1;
}
// read page tree
- catDict->dictLookup("Pages", &pagesDict);
+ catDict.dictLookup("Pages", &pagesDict);
// This should really be isDict("Pages"), but I've seen at least one
// PDF file where the /Type entry is missing.
if (!pagesDict.isDict()) {
@@ -64,25 +68,24 @@ Catalog::Catalog(Object *catDict) {
pageRefs[i].num = -1;
pageRefs[i].gen = -1;
}
- numPages = readPageTree(pagesDict.getDict(), NULL, 0);
+ numPages = readPageTree(pagesDict.getDict(), NULL, 0, printCommands);
if (numPages != numPages0) {
error(-1, "Page count in top-level pages object is incorrect");
}
pagesDict.free();
// read named destination dictionary
- catDict->dictLookup("Dests", &dests);
+ catDict.dictLookup("Dests", &dests);
// read root of named destination tree
- if (catDict->dictLookup("Names", &obj)->isDict())
+ if (catDict.dictLookup("Names", &obj)->isDict())
obj.dictLookup("Dests", &nameTree);
else
nameTree.initNull();
obj.free();
// read base URI
- baseURI = NULL;
- if (catDict->dictLookup("URI", &obj)->isDict()) {
+ if (catDict.dictLookup("URI", &obj)->isDict()) {
if (obj.dictLookup("Base", &obj2)->isString()) {
baseURI = obj2.getString()->copy();
}
@@ -90,6 +93,7 @@ Catalog::Catalog(Object *catDict) {
}
obj.free();
+ catDict.free();
return;
err3:
@@ -97,6 +101,7 @@ Catalog::Catalog(Object *catDict) {
err2:
pagesDict.free();
err1:
+ catDict.free();
dests.initNull();
nameTree.initNull();
ok = gFalse;
@@ -121,7 +126,8 @@ Catalog::~Catalog() {
}
}
-int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
+int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
+ GBool printCommands) {
Object kids;
Object kid;
Object kidRef;
@@ -140,7 +146,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
kids.arrayGet(i, &kid);
if (kid.isDict("Page")) {
attrs2 = new PageAttrs(attrs1, kid.getDict());
- page = new Page(start+1, kid.getDict(), attrs2);
+ page = new Page(xref, start+1, kid.getDict(), attrs2, printCommands);
if (!page->isOk()) {
++start;
goto err3;
@@ -166,7 +172,8 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) {
// This should really be isDict("Pages"), but I've seen at least one
// PDF file where the /Type entry is missing.
} else if (kid.isDict()) {
- if ((start = readPageTree(kid.getDict(), attrs1, start)) < 0)
+ if ((start = readPageTree(kid.getDict(), attrs1, start, printCommands))
+ < 0)
goto err2;
} else {
error(-1, "Kid object (page %d) is wrong type (%s)",
diff --git a/pdftops/Catalog.h b/pdftops/Catalog.h
index b0f3143233..5bf0c74a79 100644
--- a/pdftops/Catalog.h
+++ b/pdftops/Catalog.h
@@ -13,6 +13,7 @@
#pragma interface
#endif
+class XRef;
class Object;
class Page;
class PageAttrs;
@@ -27,7 +28,7 @@ class Catalog {
public:
// Constructor.
- Catalog(Object *catDict);
+ Catalog(XRef *xrefA, GBool printCommands = gFalse);
// Destructor.
~Catalog();
@@ -57,6 +58,7 @@ public:
private:
+ XRef *xref; // the xref table for this PDF file
Page **pages; // array of pages
Ref *pageRefs; // object ID for each page
int numPages; // number of pages
@@ -66,7 +68,8 @@ private:
GString *baseURI; // base URI for URI-type links
GBool ok; // true if catalog is valid
- int readPageTree(Dict *pages, PageAttrs *attrs, int start);
+ int readPageTree(Dict *pages, PageAttrs *attrs, int start,
+ GBool printCommands);
Object *findDestInTree(Object *tree, GString *name, Object *obj);
};
diff --git a/pdftops/CompactFontInfo.h b/pdftops/CompactFontInfo.h
index 159f4bf36b..c642660297 100644
--- a/pdftops/CompactFontInfo.h
+++ b/pdftops/CompactFontInfo.h
@@ -9,7 +9,7 @@
#ifndef COMPACTFONTINFO_H
#define COMPACTFONTINFO_H
-static const char *type1CStdStrings[391] = {
+static char *type1CStdStrings[391] = {
".notdef",
"space",
"exclam",
diff --git a/pdftops/Decrypt.cxx b/pdftops/Decrypt.cxx
index ae9b73239d..623f59417f 100644
--- a/pdftops/Decrypt.cxx
+++ b/pdftops/Decrypt.cxx
@@ -28,42 +28,96 @@ static Guchar passwordPad[32] = {
// Decrypt
//------------------------------------------------------------------------
-Decrypt::Decrypt(Guchar *fileKey, int objNum, int objGen) {
+Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) {
+ int i;
+
// construct object key
- objKey[0] = fileKey[0];
- objKey[1] = fileKey[1];
- objKey[2] = fileKey[2];
- objKey[3] = fileKey[3];
- objKey[4] = fileKey[4];
- objKey[5] = objNum & 0xff;
- objKey[6] = (objNum >> 8) & 0xff;
- objKey[7] = (objNum >> 16) & 0xff;
- objKey[8] = objGen & 0xff;
- objKey[9] = (objGen >> 8) & 0xff;
- md5(objKey, 10, objKey);
+ for (i = 0; i < keyLength; ++i) {
+ objKey[i] = fileKey[i];
+ }
+ objKey[keyLength] = objNum & 0xff;
+ objKey[keyLength + 1] = (objNum >> 8) & 0xff;
+ objKey[keyLength + 2] = (objNum >> 16) & 0xff;
+ objKey[keyLength + 3] = objGen & 0xff;
+ objKey[keyLength + 4] = (objGen >> 8) & 0xff;
+ md5(objKey, keyLength + 5, objKey);
// set up for decryption
x = y = 0;
- rc4InitKey(objKey, 10, state);
+ if ((objKeyLength = keyLength + 5) > 16) {
+ objKeyLength = 16;
+ }
+ rc4InitKey(objKey, objKeyLength, state);
}
void Decrypt::reset() {
x = y = 0;
- rc4InitKey(objKey, 10, state);
+ rc4InitKey(objKey, objKeyLength, state);
}
Guchar Decrypt::decryptByte(Guchar c) {
return rc4DecryptByte(state, &x, &y, c);
}
-GBool Decrypt::makeFileKey(GString *ownerKey, GString *userKey,
+GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
- GString *userPassword, Guchar *fileKey) {
- Guchar *buf;
- Guchar userTest[32];
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool *ownerPasswordOk) {
+ Guchar test[32];
+ GString *userPassword2;
Guchar fState[256];
Guchar fx, fy;
int len, i;
+
+ // try using the supplied owner password to generate the user password
+ if (ownerPassword) {
+ len = ownerPassword->getLength();
+ if (len < 32) {
+ memcpy(test, ownerPassword->getCString(), len);
+ memcpy(test + len, passwordPad, 32 - len);
+ } else {
+ memcpy(test, ownerPassword->getCString(), 32);
+ }
+ } else {
+ memcpy(test, passwordPad, 32);
+ }
+ md5(test, 32, test);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(test, 16, test);
+ }
+ }
+ rc4InitKey(test, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
+ }
+ userPassword2 = new GString((char *)test, 32);
+ if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword2, fileKey)) {
+ *ownerPasswordOk = gTrue;
+ delete userPassword2;
+ return gTrue;
+ }
+ *ownerPasswordOk = gFalse;
+ delete userPassword2;
+
+ // try using the supplied user password
+ return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword, fileKey);
+}
+
+GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey) {
+ Guchar *buf;
+ Guchar test[32];
+ Guchar fState[256];
+ Guchar tmpKey[16];
+ Guchar fx, fy;
+ int len, i, j;
GBool ok;
// generate file key
@@ -86,16 +140,41 @@ GBool Decrypt::makeFileKey(GString *ownerKey, GString *userKey,
buf[67] = (permissions >> 24) & 0xff;
memcpy(buf + 68, fileID->getCString(), fileID->getLength());
md5(buf, 68 + fileID->getLength(), fileKey);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(fileKey, 16, fileKey);
+ }
+ }
- // test user key
- fx = fy = 0;
- rc4InitKey(fileKey, 5, fState);
- for (i = 0; i < 32; ++i) {
- userTest[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
+ // test user password
+ if (encRevision == 2) {
+ rc4InitKey(fileKey, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
+ }
+ ok = memcmp(test, passwordPad, 32) == 0;
+ } else if (encRevision == 3) {
+ memcpy(test, userKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = fileKey[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]);
+ }
+ }
+ memcpy(buf, passwordPad, 32);
+ memcpy(buf + 32, fileID->getCString(), fileID->getLength());
+ md5(buf, 32 + fileID->getLength(), buf);
+ ok = memcmp(test, buf, 16) == 0;
+ } else {
+ ok = gFalse;
}
- ok = memcmp(userTest, passwordPad, 32) == 0;
- gfree(buf);
+ gfree(buf);
return ok;
}
@@ -136,6 +215,7 @@ static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) {
// MD5 message digest
//------------------------------------------------------------------------
+// this works around a bug in older Sun compilers
static inline Gulong rotateLeft(Gulong x, int r) {
x &= 0xffffffff;
return ((x << r) | (x >> (32 - r))) & 0xffffffff;
diff --git a/pdftops/Decrypt.h b/pdftops/Decrypt.h
index 3ea43741dc..1bdb2b7ec2 100644
--- a/pdftops/Decrypt.h
+++ b/pdftops/Decrypt.h
@@ -24,7 +24,7 @@ class Decrypt {
public:
// Initialize the decryptor object.
- Decrypt(Guchar *fileKey, int objNum, int objGen);
+ Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen);
// Reset decryption.
void reset();
@@ -32,16 +32,26 @@ public:
// Decrypt one byte.
Guchar decryptByte(Guchar c);
- // Generate a file key. The buffer must have space for
- // at least 16 bytes. Checks user key and returns gTrue if okay.
- // may be NULL.
- static GBool makeFileKey(GString *ownerKey, GString *userKey,
+ // Generate a file key. The buffer must have space for at
+ // least 16 bytes. Checks and then
+ // and returns true if either is correct. Sets if
+ // the owner password was correct. Either or both of the passwords
+ // may be NULL, which is treated as an empty string.
+ static GBool makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
int permissions, GString *fileID,
- GString *userPassword, Guchar *fileKey);
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool *ownerPasswordOk);
private:
- Guchar objKey[16];
+ static GBool makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey);
+
+ int objKeyLength;
+ Guchar objKey[21];
Guchar state[256];
Guchar x, y;
};
diff --git a/pdftops/Dict.cxx b/pdftops/Dict.cxx
index 9ec4815bd9..1ebadfce0a 100644
--- a/pdftops/Dict.cxx
+++ b/pdftops/Dict.cxx
@@ -21,7 +21,8 @@
// Dict
//------------------------------------------------------------------------
-Dict::Dict() {
+Dict::Dict(XRef *xrefA) {
+ xref = xrefA;
entries = NULL;
size = length = 0;
ref = 1;
@@ -31,13 +32,13 @@ Dict::~Dict() {
int i;
for (i = 0; i < length; ++i) {
- gfree((void *)entries[i].key);
+ gfree(entries[i].key);
entries[i].val.free();
}
gfree(entries);
}
-void Dict::add(const char *key, Object *val) {
+void Dict::add(char *key, Object *val) {
if (length + 1 > size) {
size += 8;
entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry));
@@ -47,7 +48,7 @@ void Dict::add(const char *key, Object *val) {
++length;
}
-inline DictEntry *Dict::find(const char *key) {
+inline DictEntry *Dict::find(char *key) {
int i;
for (i = 0; i < length; ++i) {
@@ -57,30 +58,30 @@ inline DictEntry *Dict::find(const char *key) {
return NULL;
}
-GBool Dict::is(const char *type) {
+GBool Dict::is(char *type) {
DictEntry *e;
return (e = find("Type")) && e->val.isName(type);
}
-Object *Dict::lookup(const char *key, Object *obj) {
+Object *Dict::lookup(char *key, Object *obj) {
DictEntry *e;
- return (e = find(key)) ? e->val.fetch(obj) : obj->initNull();
+ return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull();
}
-Object *Dict::lookupNF(const char *key, Object *obj) {
+Object *Dict::lookupNF(char *key, Object *obj) {
DictEntry *e;
return (e = find(key)) ? e->val.copy(obj) : obj->initNull();
}
-const char *Dict::getKey(int i) {
+char *Dict::getKey(int i) {
return entries[i].key;
}
Object *Dict::getVal(int i, Object *obj) {
- return entries[i].val.fetch(obj);
+ return entries[i].val.fetch(xref, obj);
}
Object *Dict::getValNF(int i, Object *obj) {
diff --git a/pdftops/Dict.h b/pdftops/Dict.h
index 37f656587c..c4f1ea58d4 100644
--- a/pdftops/Dict.h
+++ b/pdftops/Dict.h
@@ -20,7 +20,7 @@
//------------------------------------------------------------------------
struct DictEntry {
- const char *key;
+ char *key;
Object val;
};
@@ -28,7 +28,7 @@ class Dict {
public:
// Constructor.
- Dict();
+ Dict(XRef *xrefA);
// Destructor.
~Dict();
@@ -41,29 +41,35 @@ public:
int getLength() { return length; }
// Add an entry. NB: does not copy key.
- void add(const char *key, Object *val);
+ void add(char *key, Object *val);
// Check if dictionary is of specified type.
- GBool is(const char *type);
+ GBool is(char *type);
// Look up an entry and return the value. Returns a null object
// if is not in the dictionary.
- Object *lookup(const char *key, Object *obj);
- Object *lookupNF(const char *key, Object *obj);
+ Object *lookup(char *key, Object *obj);
+ Object *lookupNF(char *key, Object *obj);
// Iterative accessors.
- const char *getKey(int i);
+ char *getKey(int i);
Object *getVal(int i, Object *obj);
Object *getValNF(int i, Object *obj);
+ // Set the xref pointer. This is only used in one special case: the
+ // trailer dictionary, which is read before the xref table is
+ // parsed.
+ void setXRef(XRef *xrefA) { xref = xrefA; }
+
private:
+ XRef *xref; // the xref table for this PDF file
DictEntry *entries; // array of entries
int size; // size of array
int length; // number of entries in dictionary
int ref; // reference count
- DictEntry *find(const char *key);
+ DictEntry *find(char *key);
};
#endif
diff --git a/pdftops/Error.cxx b/pdftops/Error.cxx
index 96a96d2bf2..81010e0199 100644
--- a/pdftops/Error.cxx
+++ b/pdftops/Error.cxx
@@ -34,13 +34,10 @@ void CDECL error(int pos, const char *msg, ...) {
if (errQuiet) {
return;
}
- if (printCommands) {
- fflush(stdout);
- }
if (pos >= 0) {
- fprintf(errFile, "ERROR: (%d): ", pos);
+ fprintf(errFile, "Error (%d): ", pos);
} else {
- fprintf(errFile, "ERROR: ");
+ fprintf(errFile, "Error: ");
}
va_start(args, msg);
vfprintf(errFile, msg, args);
diff --git a/pdftops/FontEncoding.cxx b/pdftops/FontEncoding.cxx
index f526445019..3d084cc9da 100644
--- a/pdftops/FontEncoding.cxx
+++ b/pdftops/FontEncoding.cxx
@@ -21,7 +21,7 @@
// FontEncoding
//------------------------------------------------------------------------
-inline int FontEncoding::hash(const char *name) {
+inline int FontEncoding::hash(char *name) {
Guint h;
h = (Guint)name[0] & 0xff;
@@ -33,7 +33,7 @@ inline int FontEncoding::hash(const char *name) {
FontEncoding::FontEncoding() {
int i;
- encoding = (const char **)gmalloc(256 * sizeof(const char *));
+ encoding = (char **)gmalloc(256 * sizeof(char *));
size = 256;
freeEnc = gTrue;
for (i = 0; i < 256; ++i)
@@ -42,24 +42,24 @@ FontEncoding::FontEncoding() {
hashTab[i] = -1;
}
-FontEncoding::FontEncoding(const char **nencoding, int nsize) {
+FontEncoding::FontEncoding(char **encodingA, int sizeA) {
int i;
- encoding = nencoding;
- size = nsize;
+ encoding = encodingA;
+ size = sizeA;
freeEnc = gFalse;
for (i = 0; i < fontEncHashSize; ++i)
hashTab[i] = -1;
for (i = 0; i < size; ++i) {
- if (nencoding[i])
- addChar1(i, nencoding[i]);
+ if (encoding[i])
+ addChar1(i, encoding[i]);
}
}
FontEncoding::FontEncoding(FontEncoding *fontEnc) {
int i;
- encoding = (const char **)gmalloc(fontEnc->size * sizeof(const char *));
+ encoding = (char **)gmalloc(fontEnc->size * sizeof(char *));
size = fontEnc->size;
freeEnc = gTrue;
for (i = 0; i < size; ++i) {
@@ -69,7 +69,7 @@ FontEncoding::FontEncoding(FontEncoding *fontEnc) {
memcpy(hashTab, fontEnc->hashTab, fontEncHashSize * sizeof(short));
}
-void FontEncoding::addChar(int code, const char *name) {
+void FontEncoding::addChar(int code, char *name) {
int h, i;
// replace character associated with code
@@ -83,7 +83,7 @@ void FontEncoding::addChar(int code, const char *name) {
if (++h == fontEncHashSize)
h = 0;
}
- gfree((void *)encoding[code]);
+ gfree(encoding[code]);
}
// associate name with code
@@ -93,7 +93,7 @@ void FontEncoding::addChar(int code, const char *name) {
addChar1(code, name);
}
-void FontEncoding::addChar1(int code, const char *name) {
+void FontEncoding::addChar1(int code, char *name) {
int h, i, code2;
// insert name in hash table
@@ -121,13 +121,13 @@ FontEncoding::~FontEncoding() {
if (freeEnc) {
for (i = 0; i < size; ++i) {
if (encoding[i])
- gfree((void *)encoding[i]);
+ gfree(encoding[i]);
}
- gfree((void *)encoding);
+ gfree(encoding);
}
}
-int FontEncoding::getCharCode(const char *name) {
+int FontEncoding::getCharCode(char *name) {
int h, i, code;
h = hash(name);
diff --git a/pdftops/FontEncoding.h b/pdftops/FontEncoding.h
index 120858b9bd..9a5695dbe5 100644
--- a/pdftops/FontEncoding.h
+++ b/pdftops/FontEncoding.h
@@ -28,7 +28,7 @@ public:
FontEncoding();
// Construct an encoding from an array of char names.
- FontEncoding(const char **encoding, int size);
+ FontEncoding(char **encodingA, int sizeA);
// Destructor.
~FontEncoding();
@@ -40,21 +40,21 @@ public:
int getSize() { return size; }
// Add a char to the encoding.
- void addChar(int code, const char *name);
+ void addChar(int code, char *name);
// Return the character name associated with .
- const char *getCharName(int code) { return encoding[code]; }
+ char *getCharName(int code) { return encoding[code]; }
// Return the code associated with .
- int getCharCode(const char *name);
+ int getCharCode(char *name);
private:
FontEncoding(FontEncoding *fontEnc);
- int hash(const char *name);
- void addChar1(int code, const char *name);
+ int hash(char *name);
+ void addChar1(int code, char *name);
- const char **encoding; // code --> name mapping
+ char **encoding; // code --> name mapping
int size; // number of codes
GBool freeEnc; // should we free the encoding array?
short // name --> code hash table
diff --git a/pdftops/FontFile.cxx b/pdftops/FontFile.cxx
index 5ec923a0db..4054db7cd0 100644
--- a/pdftops/FontFile.cxx
+++ b/pdftops/FontFile.cxx
@@ -32,7 +32,7 @@ static char *getString(int sid, Guchar *stringIdxPtr,
//------------------------------------------------------------------------
-static inline const char *nextLine(const char *line, const char *end) {
+static inline char *nextLine(char *line, char *end) {
while (line < end && *line != '\n' && *line != '\r')
++line;
while (line < end && *line == '\n' || *line == '\r')
@@ -56,9 +56,8 @@ FontFile::~FontFile() {
// Type1FontFile
//------------------------------------------------------------------------
-Type1FontFile::Type1FontFile(const char *file, int len) {
- const char *line, *line1;
- char *p, *p2;
+Type1FontFile::Type1FontFile(char *file, int len) {
+ char *line, *line1, *p, *p2;
char buf[256];
char c;
int n, code, i;
@@ -125,7 +124,7 @@ Type1FontFile::Type1FontFile(const char *file, int len) {
Type1FontFile::~Type1FontFile() {
if (name)
- gfree((void *)name);
+ gfree(name);
if (encoding && freeEnc)
delete encoding;
}
@@ -140,11 +139,11 @@ FontEncoding *Type1FontFile::getEncoding(GBool taken) {
// Type1CFontFile
//------------------------------------------------------------------------
-Type1CFontFile::Type1CFontFile(const char *file, int len) {
+Type1CFontFile::Type1CFontFile(char *file, int len) {
char buf[256];
Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
Guchar *stringIdxPtr, *stringStartPtr;
- int idxOffSize, stringOffSize;
+ int topOffSize, idxOffSize, stringOffSize;
int nFonts, nStrings, nGlyphs;
int nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
@@ -157,14 +156,13 @@ Type1CFontFile::Type1CFontFile(const char *file, int len) {
int key;
int i, j, n;
- (void)len;
-
name = NULL;
encoding = NULL;
freeEnc = gTrue;
// read header
topPtr = (Guchar *)file + (file[2] & 0xff);
+ topOffSize = file[3] & 0xff;
// read name index (first font only)
nFonts = getWord(topPtr, 2);
@@ -175,7 +173,7 @@ Type1CFontFile::Type1CFontFile(const char *file, int len) {
idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
if ((n = idxPtr1 - idxPtr0) > 255)
n = 255;
- strncpy(buf, (const char *)idxPtr0, n);
+ strncpy(buf, (char *)idxPtr0, n);
buf[n] = '\0';
name = copyString(buf);
topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
@@ -318,7 +316,7 @@ Type1CFontFile::Type1CFontFile(const char *file, int len) {
Type1CFontFile::~Type1CFontFile() {
if (name)
- gfree((void *)name);
+ gfree(name);
if (encoding && freeEnc)
delete encoding;
}
@@ -415,7 +413,7 @@ static char *getString(int sid, Guchar *stringIdxPtr,
stringOffSize);
if ((len = idxPtr1 - idxPtr0) > 255)
len = 255;
- strncpy(buf, (const char *)idxPtr0, len);
+ strncpy(buf, (char *)idxPtr0, len);
buf[len] = '\0';
}
return buf;
@@ -425,10 +423,10 @@ static char *getString(int sid, Guchar *stringIdxPtr,
// Type1CFontConverter
//------------------------------------------------------------------------
-Type1CFontConverter::Type1CFontConverter(const char *nfile, int nlen, FILE *nout) {
- file = nfile;
- len = nlen;
- out = nout;
+Type1CFontConverter::Type1CFontConverter(char *fileA, int lenA, FILE *outA) {
+ file = fileA;
+ len = lenA;
+ out = outA;
r1 = 55665;
line = 0;
}
@@ -437,7 +435,7 @@ Type1CFontConverter::~Type1CFontConverter() {
}
void Type1CFontConverter::convert() {
- const char *fontName;
+ char *fontName;
struct {
int version;
int notice;
@@ -464,7 +462,7 @@ void Type1CFontConverter::convert() {
char buf[256], eBuf[256];
Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1;
Guchar *stringIdxPtr, *stringStartPtr;
- int idxOffSize, stringOffSize;
+ int topOffSize, idxOffSize, stringOffSize;
int nFonts, nStrings, nGlyphs;
int nCodes, nRanges, nLeft, nSups;
Gushort *glyphNames;
@@ -479,6 +477,7 @@ void Type1CFontConverter::convert() {
// read header
topPtr = (Guchar *)file + (file[2] & 0xff);
+ topOffSize = file[3] & 0xff;
// read name (first font only)
nFonts = getWord(topPtr, 2);
@@ -489,7 +488,7 @@ void Type1CFontConverter::convert() {
idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize);
if ((n = idxPtr1 - idxPtr0) > 255)
n = 255;
- strncpy(buf, (const char *)idxPtr0, n);
+ strncpy(buf, (char *)idxPtr0, n);
buf[n] = '\0';
fontName = copyString(buf);
topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize);
@@ -587,8 +586,15 @@ void Type1CFontConverter::convert() {
topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize,
stringOffSize);
- // skip global subrs
+#if 1 //~
+ // get global subrs
+ int nGSubrs;
+ int gSubrOffSize;
+
+ nGSubrs = getWord(topPtr, 2);
+ gSubrOffSize = topPtr[2];
topPtr += 3;
+#endif
// write header and font dictionary, up to encoding
fprintf(out, "%%!FontType1-1.0: %s", fontName);
@@ -845,7 +851,7 @@ void Type1CFontConverter::convert() {
nominalWidthXFP = fp[0];
break;
default:
- error(-1, "Uknown Type 1C private dict entry %04x", key);
+ error(-1, "Unknown Type 1C private dict entry %04x", key);
break;
}
i = 0;
@@ -918,11 +924,11 @@ void Type1CFontConverter::convert() {
// clean up
if (dict.charset > 2)
- gfree((void *)glyphNames);
- gfree((void *)fontName);
+ gfree(glyphNames);
+ gfree(fontName);
}
-void Type1CFontConverter::eexecWrite(const char *s) {
+void Type1CFontConverter::eexecWrite(char *s) {
Guchar *p;
Guchar x;
@@ -939,7 +945,7 @@ void Type1CFontConverter::eexecWrite(const char *s) {
}
}
-void Type1CFontConverter::cvtGlyph(const char *name, Guchar *s, int n) {
+void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) {
int nHints;
int x;
GBool first = gTrue;
@@ -1509,12 +1515,12 @@ void Type1CFontConverter::cvtGlyphWidth(GBool useOp) {
eexecDumpOp1(13);
}
-void Type1CFontConverter::eexecDumpNum(double x, GBool nfp) {
+void Type1CFontConverter::eexecDumpNum(double x, GBool fpA) {
Guchar buf[12];
int y, n;
n = 0;
- if (nfp) {
+ if (fpA) {
if (x >= -32768 && x < 32768) {
y = (int)(x * 256.0);
buf[0] = 255;
@@ -1557,16 +1563,16 @@ void Type1CFontConverter::eexecDumpNum(double x, GBool nfp) {
n = 5;
}
}
- charBuf->append((const char *)buf, n);
+ charBuf->append((char *)buf, n);
}
-void Type1CFontConverter::eexecDumpOp1(int nop) {
- charBuf->append((char)nop);
+void Type1CFontConverter::eexecDumpOp1(int opA) {
+ charBuf->append((char)opA);
}
-void Type1CFontConverter::eexecDumpOp2(int nop) {
+void Type1CFontConverter::eexecDumpOp2(int opA) {
charBuf->append((char)12);
- charBuf->append((char)nop);
+ charBuf->append((char)opA);
}
void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
@@ -1595,7 +1601,7 @@ void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) {
}
}
-void Type1CFontConverter::getDeltaInt(char *buf, const char *name, double *nop,
+void Type1CFontConverter::getDeltaInt(char *buf, char *name, double *opA,
int n) {
int x, i;
@@ -1603,14 +1609,14 @@ void Type1CFontConverter::getDeltaInt(char *buf, const char *name, double *nop,
buf += strlen(buf);
x = 0;
for (i = 0; i < n; ++i) {
- x += (int)nop[i];
+ x += (int)opA[i];
sprintf(buf, "%s%d", i > 0 ? " " : "", x);
buf += strlen(buf);
}
sprintf(buf, "] def\n");
}
-void Type1CFontConverter::getDeltaReal(char *buf, const char *name, double *nop,
+void Type1CFontConverter::getDeltaReal(char *buf, char *name, double *opA,
int n) {
double x;
int i;
@@ -1619,9 +1625,906 @@ void Type1CFontConverter::getDeltaReal(char *buf, const char *name, double *nop,
buf += strlen(buf);
x = 0;
for (i = 0; i < n; ++i) {
- x += nop[i];
+ x += opA[i];
sprintf(buf, "%s%g", i > 0 ? " " : "", x);
buf += strlen(buf);
}
sprintf(buf, "] def\n");
}
+
+//------------------------------------------------------------------------
+// TrueTypeFontFile
+//------------------------------------------------------------------------
+
+//
+// Terminology
+// -----------
+//
+// character code = number used as an element of a text string
+//
+// character name = glyph name = name for a particular glyph within a
+// font
+//
+// glyph index = position (within some internal table in the font)
+// where the instructions to draw a particular glyph are
+// stored
+//
+// Type 1 fonts
+// ------------
+//
+// Type 1 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of instructions, keyed by character names,
+// maps character name to glyph data
+//
+// CharStrings[charName] = glyphData
+//
+// TrueType fonts
+// --------------
+//
+// TrueType fonts contain:
+//
+// 'cmap' table: mapping from character code to glyph index; there may
+// be multiple cmaps in a TrueType font
+//
+// cmap[charCode] = glyphIdx
+//
+// 'post' table: mapping from glyph index to glyph name
+//
+// post[glyphIdx] = glyphName
+//
+// Type 42 fonts
+// -------------
+//
+// Type 42 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of glyph indexes, keyed by character names,
+// maps character name to glyph index
+//
+// CharStrings[charName] = glyphIdx
+//
+
+struct TTFontTableHdr {
+ char tag[4];
+ Guint checksum;
+ Guint offset;
+ Guint length;
+};
+
+// TrueType tables required by the Type 42 spec.
+static char *t42ReqTables[9] = {
+ "head",
+ "hhea",
+ "loca",
+ "maxp",
+ "cvt ",
+ "prep",
+ "glyf",
+ "hmtx",
+ "fpgm"
+};
+
+// Glyph names in some arbitrary standard that Apple uses for their
+// TrueType fonts.
+static char *macGlyphNames[258] = {
+ ".notdef",
+ "null",
+ "CR",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "Adieresis",
+ "Aring",
+ "Ccedilla",
+ "Eacute",
+ "Ntilde",
+ "Odieresis",
+ "Udieresis",
+ "aacute",
+ "agrave",
+ "acircumflex",
+ "adieresis",
+ "atilde",
+ "aring",
+ "ccedilla",
+ "eacute",
+ "egrave",
+ "ecircumflex",
+ "edieresis",
+ "iacute",
+ "igrave",
+ "icircumflex",
+ "idieresis",
+ "ntilde",
+ "oacute",
+ "ograve",
+ "ocircumflex",
+ "odieresis",
+ "otilde",
+ "uacute",
+ "ugrave",
+ "ucircumflex",
+ "udieresis",
+ "dagger",
+ "degree",
+ "cent",
+ "sterling",
+ "section",
+ "bullet",
+ "paragraph",
+ "germandbls",
+ "registered",
+ "copyright",
+ "trademark",
+ "acute",
+ "dieresis",
+ "notequal",
+ "AE",
+ "Oslash",
+ "infinity",
+ "plusminus",
+ "lessequal",
+ "greaterequal",
+ "yen",
+ "mu1",
+ "partialdiff",
+ "summation",
+ "product",
+ "pi",
+ "integral",
+ "ordfeminine",
+ "ordmasculine",
+ "Ohm",
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ "radical",
+ "florin",
+ "approxequal",
+ "increment",
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "nbspace",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ "lozenge",
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ "applelogo",
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "overscore",
+ "breve",
+ "dotaccent",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "Lslash",
+ "lslash",
+ "Scaron",
+ "scaron",
+ "Zcaron",
+ "zcaron",
+ "brokenbar",
+ "Eth",
+ "eth",
+ "Yacute",
+ "yacute",
+ "Thorn",
+ "thorn",
+ "minus",
+ "multiply",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "onehalf",
+ "onequarter",
+ "threequarters",
+ "franc",
+ "Gbreve",
+ "gbreve",
+ "Idot",
+ "Scedilla",
+ "scedilla",
+ "Cacute",
+ "cacute",
+ "Ccaron",
+ "ccaron",
+ "dmacron"
+};
+
+TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
+ int pos, i;
+
+ file = fileA;
+ len = lenA;
+
+ encoding = NULL;
+ freeEnc = gTrue;
+
+ // read table directory
+ nTables = getUShort(4);
+ tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr));
+ pos = 12;
+ for (i = 0; i < nTables; ++i) {
+ tableHdrs[i].tag[0] = getByte(pos+0);
+ tableHdrs[i].tag[1] = getByte(pos+1);
+ tableHdrs[i].tag[2] = getByte(pos+2);
+ tableHdrs[i].tag[3] = getByte(pos+3);
+ tableHdrs[i].checksum = getULong(pos+4);
+ tableHdrs[i].offset = getULong(pos+8);
+ tableHdrs[i].length = getULong(pos+12);
+ pos += 16;
+ }
+
+ // check for tables that are required by both the TrueType spec
+ // and the Type 42 spec
+ if (seekTable("head") < 0 ||
+ seekTable("hhea") < 0 ||
+ seekTable("loca") < 0 ||
+ seekTable("maxp") < 0 ||
+ seekTable("glyf") < 0 ||
+ seekTable("hmtx") < 0) {
+ error(-1, "TrueType font file is missing a required table");
+ return;
+ }
+
+ // read the 'head' table
+ pos = seekTable("head");
+ bbox[0] = getShort(pos + 36);
+ bbox[1] = getShort(pos + 38);
+ bbox[2] = getShort(pos + 40);
+ bbox[3] = getShort(pos + 42);
+ locaFmt = getShort(pos + 50);
+
+ // read the 'maxp' table
+ pos = seekTable("maxp");
+ nGlyphs = getUShort(pos + 4);
+}
+
+TrueTypeFontFile::~TrueTypeFontFile() {
+ if (encoding && freeEnc) {
+ delete encoding;
+ }
+ gfree(tableHdrs);
+}
+
+char *TrueTypeFontFile::getName() {
+ return NULL;
+}
+
+FontEncoding *TrueTypeFontFile::getEncoding(GBool taken) {
+ int cmap[256];
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapLen, cmapOffset;
+ int segCnt, segStart, segEnd, segDelta, segOffset;
+ int pos, i, j, k;
+ Guint fmt;
+ GString *s;
+ int stringIdx, stringPos, n;
+
+ //----- construct the (char code) -> (glyph idx) mapping
+
+ // map everything to the missing glyph
+ for (i = 0; i < 256; ++i) {
+ cmap[i] = 0;
+ }
+
+ // look for the 'cmap' table
+ if ((pos = seekTable("cmap")) >= 0) {
+ nCmaps = getUShort(pos+2);
+
+ // if the font has a Windows-symbol cmap, use it;
+ // otherwise, use the first cmap in the table
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ break;
+ }
+ }
+ if (i >= nCmaps) {
+ i = 0;
+ cmapPlatform = getUShort(pos + 4);
+ cmapEncoding = getUShort(pos + 4 + 2);
+ }
+ pos += getULong(pos + 4 + 8*i + 4);
+
+ // read the cmap
+ cmapFmt = getUShort(pos);
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ for (i = 0; i < cmapLen && i < 256; ++i) {
+ cmap[i] = getByte(pos + 6 + i);
+ }
+ break;
+ case 4: // segment mapping to delta values (Microsoft standard)
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ // Windows-symbol uses char codes 0xf000 - 0xf0ff
+ cmapOffset = 0xf000;
+ } else {
+ cmapOffset = 0;
+ }
+ segCnt = getUShort(pos + 6) / 2;
+ for (i = 0; i < segCnt; ++i) {
+ segEnd = getUShort(pos + 14 + 2*i);
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
+ if (segStart - cmapOffset <= 0xff &&
+ segEnd - cmapOffset >= 0) {
+ for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
+ j <= segEnd && j - cmapOffset <= 0xff;
+ ++j) {
+ if (segOffset == 0) {
+ k = (j + segDelta) & 0xffff;
+ } else {
+ k = getUShort(pos + 16 + 6*segCnt + 2*i +
+ segOffset + 2 * (j - segStart));
+ if (k != 0) {
+ k = (k + segDelta) & 0xffff;
+ }
+ }
+ cmap[j - cmapOffset] = k;
+ }
+ }
+ }
+ break;
+ default:
+ error(-1, "Unimplemented cmap type (%d) in TrueType font file",
+ cmapFmt);
+ break;
+ }
+ }
+
+ //----- construct the (glyph idx) -> (glyph name) mapping
+ //----- and compute the (char code) -> (glyph name) mapping
+
+ encoding = new FontEncoding();
+
+ if ((pos = seekTable("post")) >= 0) {
+ fmt = getULong(pos);
+
+ // Apple font
+ if (fmt == 0x00010000) {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+
+ // Microsoft font
+ } else if (fmt == 0x00020000) {
+ stringIdx = 0;
+ stringPos = pos + 34 + 2*nGlyphs;
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = getUShort(pos + 34 + 2 * cmap[i]);
+ if (j < 258) {
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ } else {
+ j -= 258;
+ if (j != stringIdx) {
+ for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
+ stringIdx < j;
+ ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
+ }
+ n = getByte(stringPos);
+ s = new GString(file + stringPos + 1, n);
+ encoding->addChar(i, copyString(s->getCString()));
+ delete s;
+ ++stringIdx;
+ stringPos += 1 + n;
+ }
+ } else {
+ encoding->addChar(i, copyString(macGlyphNames[0]));
+ }
+ }
+
+ // Apple subset
+ } else if (fmt == 0x000280000) {
+ for (i = 0; i < 256; ++i) {
+ if (cmap[i] < nGlyphs) {
+ j = i + getChar(pos + 32 + cmap[i]);
+ } else {
+ j = 0;
+ }
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+
+ // Ugh, just assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+ }
+
+ // no "post" table: assume the Apple glyph set
+ } else {
+ for (i = 0; i < 256; ++i) {
+ j = (cmap[i] < 258) ? cmap[i] : 0;
+ encoding->addChar(i, copyString(macGlyphNames[j]));
+ }
+ }
+
+ if (taken) {
+ freeEnc = gFalse;
+ }
+ return encoding;
+}
+
+void TrueTypeFontFile::convertToType42(char *name, FontEncoding *encodingA,
+ FILE *out) {
+ // write the header
+ fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+
+ // begin the font dictionary
+ fprintf(out, "10 dict begin\n");
+ fprintf(out, "/FontName /%s def\n", name);
+ fprintf(out, "/FontType 42 def\n");
+ fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
+ fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ fprintf(out, "/PaintType 0 def\n");
+
+ // write the guts of the dictionary
+ cvtEncoding(encodingA, out);
+ cvtCharStrings(encodingA, out);
+ cvtSfnts(out);
+
+ // end the dictionary and define the font
+ fprintf(out, "FontName currentdict end definefont pop\n");
+}
+
+int TrueTypeFontFile::getByte(int pos) {
+ return file[pos] & 0xff;
+}
+
+int TrueTypeFontFile::getChar(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ if (x & 0x80)
+ x |= 0xffffff00;
+ return x;
+}
+
+int TrueTypeFontFile::getUShort(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ return x;
+}
+
+int TrueTypeFontFile::getShort(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ if (x & 0x8000)
+ x |= 0xffff0000;
+ return x;
+}
+
+Guint TrueTypeFontFile::getULong(int pos) {
+ int x;
+
+ x = file[pos] & 0xff;
+ x = (x << 8) + (file[pos+1] & 0xff);
+ x = (x << 8) + (file[pos+2] & 0xff);
+ x = (x << 8) + (file[pos+3] & 0xff);
+ return x;
+}
+
+double TrueTypeFontFile::getFixed(int pos) {
+ int x, y;
+
+ x = getShort(pos);
+ y = getUShort(pos+2);
+ return (double)x + (double)y / 65536;
+}
+
+int TrueTypeFontFile::seekTable(char *tag) {
+ int i;
+
+ for (i = 0; i < nTables; ++i) {
+ if (!strncmp(tableHdrs[i].tag, tag, 4))
+ return tableHdrs[i].offset;
+ }
+ return -1;
+}
+
+void TrueTypeFontFile::cvtEncoding(FontEncoding *encodingA, FILE *out) {
+ char *name;
+ int i;
+
+ fprintf(out, "/Encoding 256 array\n");
+ for (i = 0; i < 256; ++i) {
+ if (!(name = encodingA->getCharName(i))) {
+ name = ".notdef";
+ }
+ fprintf(out, "dup %d /%s put\n", i, name);
+ }
+ fprintf(out, "readonly def\n");
+}
+
+void TrueTypeFontFile::cvtCharStrings(FontEncoding *encodingA, FILE *out) {
+ int cmap[256];
+ int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapLen, cmapOffset;
+ int segCnt, segStart, segEnd, segDelta, segOffset;
+ char *name;
+ int pos, i, j, k;
+
+ //----- read the cmap: construct the (char code) -> (glyph idx) mapping
+
+ // map everything to the missing glyph
+ for (i = 0; i < 256; ++i) {
+ cmap[i] = 0;
+ }
+
+ // look for the 'cmap' table
+ if ((pos = seekTable("cmap")) >= 0) {
+ nCmaps = getUShort(pos+2);
+
+ // if the font has a Windows-symbol cmap, use it;
+ // otherwise, use the first cmap in the table
+ for (i = 0; i < nCmaps; ++i) {
+ cmapPlatform = getUShort(pos + 4 + 8*i);
+ cmapEncoding = getUShort(pos + 4 + 8*i + 2);
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ break;
+ }
+ }
+ if (i >= nCmaps) {
+ i = 0;
+ cmapPlatform = getUShort(pos + 4);
+ cmapEncoding = getUShort(pos + 4 + 2);
+ }
+ pos += getULong(pos + 4 + 8*i + 4);
+
+ // read the cmap
+ cmapFmt = getUShort(pos);
+ switch (cmapFmt) {
+ case 0: // byte encoding table (Apple standard)
+ cmapLen = getUShort(pos + 2);
+ for (i = 0; i < cmapLen && i < 256; ++i) {
+ cmap[i] = getByte(pos + 6 + i);
+ }
+ break;
+ case 4: // segment mapping to delta values (Microsoft standard)
+ if (cmapPlatform == 3 && cmapEncoding == 0) {
+ // Windows-symbol uses char codes 0xf000 - 0xf0ff
+ cmapOffset = 0xf000;
+ } else {
+ cmapOffset = 0;
+ }
+ segCnt = getUShort(pos + 6) / 2;
+ for (i = 0; i < segCnt; ++i) {
+ segEnd = getUShort(pos + 14 + 2*i);
+ segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
+ segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
+ segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
+ if (segStart - cmapOffset <= 0xff &&
+ segEnd - cmapOffset >= 0) {
+ for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
+ j <= segEnd && j - cmapOffset <= 0xff;
+ ++j) {
+ if (segOffset == 0) {
+ k = (j + segDelta) & 0xffff;
+ } else {
+ k = getUShort(pos + 16 + 6*segCnt + 2*i +
+ segOffset + 2 * (j - segStart));
+ if (k != 0) {
+ k = (k + segDelta) & 0xffff;
+ }
+ }
+ cmap[j - cmapOffset] = k;
+ }
+ }
+ }
+ break;
+ default:
+ error(-1, "Unimplemented cmap type (%d) in TrueType font file",
+ cmapFmt);
+ break;
+ }
+ }
+
+ //----- map char code to glyph index
+
+ // 1. use encoding to map name to char code
+ // 2. use cmap to map char code to glyph index
+
+ fprintf(out, "/CharStrings 256 dict dup begin\n");
+ fprintf(out, "/.notdef 0 def\n");
+
+ // kludge: this loop goes backward because the WinAnsi and MacRoman
+ // encodings define certain chars multiple times (space, hyphen,
+ // etc.), and we want the lowest-numbered definition to "stick"
+ // (because the higher-numbered defn(s) may not have valid cmap
+ // entries)
+ i = encodingA->getSize();
+ if (i > 255) {
+ i = 255;
+ }
+ for (; i >= 0; --i) {
+ name = encodingA->getCharName(i);
+ if (name && strcmp(name, ".notdef")) {
+ fprintf(out, "/%s %d def\n", name, cmap[i]);
+ }
+ }
+
+ fprintf(out, "end readonly def\n");
+}
+
+void TrueTypeFontFile::cvtSfnts(FILE *out) {
+ char tableDir[12 + 9*16];
+ int *list;
+ int nTablesOut, pos, destPos, i, j, k1, k2;
+
+ fprintf(out, "/sfnts [\n");
+
+ // count tables
+ nTablesOut = 0;
+ for (i = 0; i < 9; ++i) {
+ for (j = 0; j < nTables; ++j) {
+ if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) {
+ ++nTablesOut;
+ break;
+ }
+ }
+ }
+
+ // header
+ tableDir[0] = 0x00; // sfnt version
+ tableDir[1] = 0x01;
+ tableDir[2] = 0x00;
+ tableDir[3] = 0x00;
+ tableDir[4] = (nTablesOut >> 8) & 0xff; // numTables
+ tableDir[5] = nTablesOut & 0xff;
+ tableDir[6] = 0; // searchRange
+ tableDir[7] = (char)128;
+ tableDir[8] = 0; // entrySelector
+ tableDir[9] = 3;
+ tableDir[10] = 0; // rangeShift
+ tableDir[11] = 16;
+
+ // table directory
+ pos = 12;
+ destPos = 12 + 16 * nTablesOut;
+ for (i = 0; i < 9; ++i) {
+ for (j = 0; j < nTables; ++j) {
+ if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) {
+ break;
+ }
+ }
+ if (j < nTables) {
+ memcpy(&tableDir[pos], t42ReqTables[i], 4);
+ tableDir[pos+4] = (tableHdrs[j].checksum >> 24) & 0xff;
+ tableDir[pos+5] = (tableHdrs[j].checksum >> 16) & 0xff;
+ tableDir[pos+6] = (tableHdrs[j].checksum >> 8) & 0xff;
+ tableDir[pos+7] = tableHdrs[j].checksum & 0xff;
+ tableDir[pos+8] = (destPos >> 24) & 0xff;
+ tableDir[pos+9] = (destPos >> 16) & 0xff;
+ tableDir[pos+10] = (destPos >> 8) & 0xff;
+ tableDir[pos+11] = destPos & 0xff;
+ tableDir[pos+12] = (tableHdrs[j].length >> 24) & 0xff;
+ tableDir[pos+13] = (tableHdrs[j].length >> 16) & 0xff;
+ tableDir[pos+14] = (tableHdrs[j].length >> 8) & 0xff;
+ tableDir[pos+15] = tableHdrs[j].length & 0xff;
+ pos += 16;
+ destPos += tableHdrs[j].length;
+ if (tableHdrs[j].length & 3) {
+ destPos += 4 - (tableHdrs[j].length & 3);
+ }
+ }
+ }
+
+ dumpString(tableDir, 12 + 16 * nTablesOut, out);
+
+ for (i = 0; i < 9; ++i) {
+ for (j = 0; j < nTables; ++j) {
+ if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) {
+ break;
+ }
+ }
+ if (j < nTables) {
+ if (!strcmp(t42ReqTables[i], "glyf") && tableHdrs[j].length > 65532) {
+ // the 'glyf' table won't fit in a single string, and we're only
+ // allowed to break at glyph boundaries
+ list = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
+ pos = seekTable("loca");
+ for (k1 = 0; k1 <= nGlyphs; ++k1) {
+ if (locaFmt) {
+ list[k1] = getULong(pos + 4*k1);
+ } else {
+ list[k1] = 2 * getUShort(pos + 2*k1);
+ }
+ }
+ k1 = 0;
+ while (k1 < nGlyphs) {
+ for (k2 = k1 + 1;
+ k2 < nGlyphs && list[k2+1] - list[k1] <= 65532;
+ ++k2) ;
+ // ghostscript is unhappy if we break at anything other
+ // than a multiple of four bytes
+ while (((list[k2] - list[k1]) & 3) && k2 > k1 + 1) {
+ --k2;
+ }
+ dumpString(file + tableHdrs[j].offset + list[k1],
+ list[k2] - list[k1], out);
+ k1 = k2;
+ }
+ gfree(list);
+ } else {
+ dumpString(file + tableHdrs[j].offset, tableHdrs[j].length, out);
+ }
+ }
+ }
+
+ fprintf(out, "] def\n");
+}
+
+void TrueTypeFontFile::dumpString(char *s, int n, FILE *out) {
+ int i, j;
+
+ fprintf(out, "<");
+ for (i = 0; i < n; i += 32) {
+ for (j = 0; j < 32 && i+j < n; ++j) {
+ fprintf(out, "%02X", s[i+j] & 0xff);
+ }
+ if (i+32 < n) {
+ fprintf(out, "\n");
+ }
+ }
+ if (n & 3) {
+ for (i = 0; i < 4 - (n & 3); ++i) {
+ fprintf(out, "00");
+ }
+ }
+ // append an extra mystery zero byte because the Type 42 spec says so
+ fprintf(out, "00>\n");
+}
diff --git a/pdftops/FontFile.h b/pdftops/FontFile.h
index 59382a962a..b64d827ebc 100644
--- a/pdftops/FontFile.h
+++ b/pdftops/FontFile.h
@@ -30,7 +30,7 @@ public:
// Returns the font name, as specified internally by the font file.
// Returns NULL if no name is available.
- virtual const char *getName() = 0;
+ virtual char *getName() = 0;
// Returns the custom font encoding, or NULL if the encoding is
// not available. If is set, the caller of this function
@@ -45,14 +45,14 @@ public:
class Type1FontFile: public FontFile {
public:
- Type1FontFile(const char *file, int len);
+ Type1FontFile(char *file, int len);
virtual ~Type1FontFile();
- virtual const char *getName() { return name; }
+ virtual char *getName() { return name; }
virtual FontEncoding *getEncoding(GBool taken);
private:
- const char *name;
+ char *name;
FontEncoding *encoding;
GBool freeEnc;
};
@@ -64,14 +64,14 @@ private:
class Type1CFontFile: public FontFile {
public:
- Type1CFontFile(const char *file, int len);
+ Type1CFontFile(char *file, int len);
virtual ~Type1CFontFile();
- virtual const char *getName() { return name; }
+ virtual char *getName() { return name; }
virtual FontEncoding *getEncoding(GBool taken);
private:
- const char *name;
+ char *name;
FontEncoding *encoding;
GBool freeEnc;
};
@@ -83,23 +83,23 @@ private:
class Type1CFontConverter {
public:
- Type1CFontConverter(const char *file, int len, FILE *out);
+ Type1CFontConverter(char *fileA, int lenA, FILE *outA);
~Type1CFontConverter();
void convert();
private:
- void eexecWrite(const char *s);
- void cvtGlyph(const char *name, Guchar *s, int n);
+ void eexecWrite(char *s);
+ void cvtGlyph(char *name, Guchar *s, int n);
void cvtGlyphWidth(GBool useOp);
- void eexecDumpNum(double x, GBool fp);
- void eexecDumpOp1(int op);
- void eexecDumpOp2(int op);
+ void eexecDumpNum(double x, GBool fpA);
+ void eexecDumpOp1(int opA);
+ void eexecDumpOp2(int opA);
void eexecWriteCharstring(Guchar *s, int n);
- void getDeltaInt(char *buf, const char *name, double *op, int n);
- void getDeltaReal(char *buf, const char *name, double *op, int n);
+ void getDeltaInt(char *buf, char *name, double *opA, int n);
+ void getDeltaReal(char *buf, char *name, double *opA, int n);
- const char *file;
+ char *file;
int len;
FILE *out;
double op[48]; // operands
@@ -114,4 +114,57 @@ private:
int line; // number of eexec chars on current line
};
+//------------------------------------------------------------------------
+// TrueTypeFontFile
+//------------------------------------------------------------------------
+
+struct TTFontTableHdr;
+
+class TrueTypeFontFile: public FontFile {
+public:
+
+ TrueTypeFontFile(char *fileA, int lenA);
+ ~TrueTypeFontFile();
+
+ // This always returns NULL, since it's probably better to trust the
+ // font name in the PDF file rather than the one in the TrueType
+ // font file.
+ virtual char *getName();
+
+ virtual FontEncoding *getEncoding(GBool taken);
+
+ // Convert to a Type 42 font, suitable for embedding in a PostScript
+ // file. The name will be used as the PostScript font name (so we
+ // don't need to depend on the 'name' table in the font). The
+ // encoding is needed because the PDF Font object can modify the
+ // encoding.
+ void convertToType42(char *name, FontEncoding *encodingA, FILE *out);
+
+private:
+
+ char *file;
+ int len;
+
+ FontEncoding *encoding;
+ GBool freeEnc;
+
+ TTFontTableHdr *tableHdrs;
+ int nTables;
+ int bbox[4];
+ int locaFmt;
+ int nGlyphs;
+
+ int getByte(int pos);
+ int getChar(int pos);
+ int getUShort(int pos);
+ int getShort(int pos);
+ Guint getULong(int pos);
+ double getFixed(int pos);
+ int seekTable(char *tag);
+ void cvtEncoding(FontEncoding *encodingA, FILE *out);
+ void cvtCharStrings(FontEncoding *encodingA, FILE *out);
+ void cvtSfnts(FILE *out);
+ void dumpString(char *s, int n, FILE *out);
+};
+
#endif
diff --git a/pdftops/FontInfo.h b/pdftops/FontInfo.h
index 9b20f0faa3..a5b4cced33 100644
--- a/pdftops/FontInfo.h
+++ b/pdftops/FontInfo.h
@@ -16,7 +16,7 @@
//------------------------------------------------------------------------
#define standardEncodingSize 335
-static const char *standardEncodingNames[standardEncodingSize] = {
+static char *standardEncodingNames[standardEncodingSize] = {
NULL,
NULL,
NULL,
@@ -357,7 +357,7 @@ static FontEncoding standardEncoding(standardEncodingNames,
standardEncodingSize);
#define symbolEncodingSize 257
-static const char *symbolEncodingNames[symbolEncodingSize] = {
+static char *symbolEncodingNames[symbolEncodingSize] = {
NULL,
NULL,
NULL,
@@ -620,7 +620,7 @@ static FontEncoding symbolEncoding(symbolEncodingNames,
symbolEncodingSize);
#define zapfDingbatsEncodingSize 270
-static const char *zapfDingbatsEncodingNames[zapfDingbatsEncodingSize] = {
+static char *zapfDingbatsEncodingNames[zapfDingbatsEncodingSize] = {
NULL,
NULL,
NULL,
@@ -896,7 +896,7 @@ static FontEncoding zapfDingbatsEncoding(zapfDingbatsEncodingNames,
zapfDingbatsEncodingSize);
#define macRomanEncodingSize 256
-static const char *macRomanEncodingNames[macRomanEncodingSize] = {
+static char *macRomanEncodingNames[macRomanEncodingSize] = {
NULL,
NULL,
NULL,
@@ -1158,7 +1158,7 @@ static FontEncoding macRomanEncoding(macRomanEncodingNames,
macRomanEncodingSize);
#define winAnsiEncodingSize 256
-static const char *winAnsiEncodingNames[winAnsiEncodingSize] = {
+static char *winAnsiEncodingNames[winAnsiEncodingSize] = {
NULL,
NULL,
NULL,
@@ -1287,7 +1287,7 @@ static const char *winAnsiEncodingNames[winAnsiEncodingSize] = {
"braceright",
"asciitilde",
"bullet",
- "bullet",
+ "Euro",
"bullet",
"quotesinglbase",
"florin",
@@ -2041,28 +2041,30 @@ static Gushort zapfDingbatsWidths[270] = {
//------------------------------------------------------------------------
struct BuiltinFont {
- const char *name;
+ char *name;
Gushort *widths;
FontEncoding *encoding;
+ short ascent;
+ short descent;
};
#define numBuiltinFonts ((int)(sizeof(builtinFonts)/sizeof(BuiltinFont)))
static BuiltinFont builtinFonts[] = {
- {"Courier", courierWidths, &standardEncoding},
- {"Courier-Bold", courierBoldWidths, &standardEncoding},
- {"Courier-BoldOblique", courierBoldObliqueWidths, &standardEncoding},
- {"Courier-Oblique", courierObliqueWidths, &standardEncoding},
- {"Helvetica", helveticaWidths, &standardEncoding},
- {"Helvetica-Bold", helveticaBoldWidths, &standardEncoding},
- {"Helvetica-BoldOblique", helveticaBoldObliqueWidths, &standardEncoding},
- {"Helvetica-Oblique", helveticaObliqueWidths, &standardEncoding},
- {"Symbol", symbolWidths, &symbolEncoding},
- {"Times-Bold", timesBoldWidths, &standardEncoding},
- {"Times-BoldItalic", timesBoldItalicWidths, &standardEncoding},
- {"Times-Italic", timesItalicWidths, &standardEncoding},
- {"Times-Roman", timesRomanWidths, &standardEncoding},
- {"ZapfDingbats", zapfDingbatsWidths, &zapfDingbatsEncoding}
+ {"Courier", courierWidths, &standardEncoding, 624, -207},
+ {"Courier-Bold", courierBoldWidths, &standardEncoding, 674, -257},
+ {"Courier-BoldOblique", courierBoldObliqueWidths, &standardEncoding, 674, -257},
+ {"Courier-Oblique", courierObliqueWidths, &standardEncoding, 624, -207},
+ {"Helvetica", helveticaWidths, &standardEncoding, 729, -219},
+ {"Helvetica-Bold", helveticaBoldWidths, &standardEncoding, 729, -219},
+ {"Helvetica-BoldOblique", helveticaBoldObliqueWidths, &standardEncoding, 729, -219},
+ {"Helvetica-Oblique", helveticaObliqueWidths, &standardEncoding, 729, -219},
+ {"Symbol", symbolWidths, &symbolEncoding, 1010, -293},
+ {"Times-Bold", timesBoldWidths, &standardEncoding, 670, -210},
+ {"Times-BoldItalic", timesBoldItalicWidths, &standardEncoding, 682, -203},
+ {"Times-Italic", timesItalicWidths, &standardEncoding, 684, -206},
+ {"Times-Roman", timesRomanWidths, &standardEncoding, 682, -217},
+ {"ZapfDingbats", zapfDingbatsWidths, &zapfDingbatsEncoding, 820, -143}
};
#endif
diff --git a/pdftops/FormWidget.cxx b/pdftops/FormWidget.cxx
index 76428d05e6..a9f8c06937 100644
--- a/pdftops/FormWidget.cxx
+++ b/pdftops/FormWidget.cxx
@@ -19,11 +19,12 @@
// FormWidget
//------------------------------------------------------------------------
-FormWidget::FormWidget(Dict *dict) {
+FormWidget::FormWidget(XRef *xrefA, Dict *dict) {
Object obj1, obj2;
double t;
ok = gFalse;
+ xref = xrefA;
if (dict->lookup("AP", &obj1)->isDict()) {
obj1.dictLookupNF("N", &obj2);
@@ -74,7 +75,7 @@ FormWidget::~FormWidget() {
void FormWidget::draw(Gfx *gfx) {
Object obj;
- if (appearance.fetch(&obj)->isStream()) {
+ if (appearance.fetch(xref, &obj)->isStream()) {
gfx->doWidgetForm(&obj, xMin, yMin, xMax, yMax);
}
obj.free();
@@ -84,7 +85,7 @@ void FormWidget::draw(Gfx *gfx) {
// FormWidgets
//------------------------------------------------------------------------
-FormWidgets::FormWidgets(Object *annots) {
+FormWidgets::FormWidgets(XRef *xref, Object *annots) {
FormWidget *widget;
Object obj1, obj2;
int size;
@@ -100,7 +101,7 @@ FormWidgets::FormWidgets(Object *annots) {
obj1.dictLookup("Subtype", &obj2);
if (obj2.isName("Widget") ||
obj2.isName("Stamp")) {
- widget = new FormWidget(obj1.getDict());
+ widget = new FormWidget(xref, obj1.getDict());
if (widget->isOk()) {
if (nWidgets >= size) {
size += 16;
diff --git a/pdftops/FormWidget.h b/pdftops/FormWidget.h
index d746083bf4..c14421e81f 100644
--- a/pdftops/FormWidget.h
+++ b/pdftops/FormWidget.h
@@ -13,6 +13,7 @@
#pragma interface
#endif
+class XRef;
class Gfx;
//------------------------------------------------------------------------
@@ -22,17 +23,18 @@ class Gfx;
class FormWidget {
public:
- FormWidget(Dict *dict);
+ FormWidget(XRef *xrefA, Dict *dict);
~FormWidget();
GBool isOk() { return ok; }
void draw(Gfx *gfx);
// Get appearance object.
- Object *getAppearance(Object *obj) { return appearance.fetch(obj); }
+ Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
private:
+ XRef *xref; // the xref table for this PDF file
Object appearance; // a reference to the Form XObject stream
// for the normal appearance
double xMin, yMin, // widget rectangle
@@ -48,7 +50,7 @@ class FormWidgets {
public:
// Extract widgets from array of annotations.
- FormWidgets(Object *annots);
+ FormWidgets(XRef *xref, Object *annots);
~FormWidgets();
diff --git a/pdftops/Gfx.cxx b/pdftops/Gfx.cxx
index fb323930da..a55efde82d 100644
--- a/pdftops/Gfx.cxx
+++ b/pdftops/Gfx.cxx
@@ -25,9 +25,20 @@
#include "GfxState.h"
#include "OutputDev.h"
#include "Params.h"
+#include "Page.h"
#include "Error.h"
#include "Gfx.h"
+//------------------------------------------------------------------------
+// constants
+//------------------------------------------------------------------------
+
+// Max number of splits along the t axis for an axial shading fill.
+#define axialMaxSplits 256
+
+// Max delta allowed in any color component for an axial shading fill.
+#define axialColorDelta (1 / 256.0)
+
//------------------------------------------------------------------------
// Operator table
//------------------------------------------------------------------------
@@ -189,15 +200,11 @@ Operator Gfx::opTab[] = {
#define numOps (sizeof(opTab) / sizeof(Operator))
-//------------------------------------------------------------------------
-
-GBool printCommands = gFalse;
-
//------------------------------------------------------------------------
// GfxResources
//------------------------------------------------------------------------
-GfxResources::GfxResources(Dict *resDict, GfxResources *next) {
+GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
Object obj1;
if (resDict) {
@@ -206,7 +213,7 @@ GfxResources::GfxResources(Dict *resDict, GfxResources *next) {
fonts = NULL;
resDict->lookup("Font", &obj1);
if (obj1.isDict()) {
- fonts = new GfxFontDict(obj1.getDict());
+ fonts = new GfxFontDict(xref, obj1.getDict());
}
obj1.free();
@@ -219,6 +226,9 @@ GfxResources::GfxResources(Dict *resDict, GfxResources *next) {
// get pattern dictionary
resDict->lookup("Pattern", &patternDict);
+ // get shading dictionary
+ resDict->lookup("Shading", &shadingDict);
+
// get graphics state parameter dictionary
resDict->lookup("ExtGState", &gStateDict);
@@ -230,7 +240,7 @@ GfxResources::GfxResources(Dict *resDict, GfxResources *next) {
gStateDict.initNull();
}
- this->next = next;
+ next = nextA;
}
GfxResources::~GfxResources() {
@@ -240,10 +250,11 @@ GfxResources::~GfxResources() {
xObjDict.free();
colorSpaceDict.free();
patternDict.free();
+ shadingDict.free();
gStateDict.free();
}
-GfxFont *GfxResources::lookupFont(const char *name) {
+GfxFont *GfxResources::lookupFont(char *name) {
GfxFont *font;
GfxResources *resPtr;
@@ -257,7 +268,7 @@ GfxFont *GfxResources::lookupFont(const char *name) {
return NULL;
}
-GBool GfxResources::lookupXObject(const char *name, Object *obj) {
+GBool GfxResources::lookupXObject(char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -271,7 +282,7 @@ GBool GfxResources::lookupXObject(const char *name, Object *obj) {
return gFalse;
}
-GBool GfxResources::lookupXObjectNF(const char *name, Object *obj) {
+GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -285,7 +296,7 @@ GBool GfxResources::lookupXObjectNF(const char *name, Object *obj) {
return gFalse;
}
-void GfxResources::lookupColorSpace(const char *name, Object *obj) {
+void GfxResources::lookupColorSpace(char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -299,7 +310,7 @@ void GfxResources::lookupColorSpace(const char *name, Object *obj) {
obj->initNull();
}
-GfxPattern *GfxResources::lookupPattern(const char *name) {
+GfxPattern *GfxResources::lookupPattern(char *name) {
GfxResources *resPtr;
GfxPattern *pattern;
Object obj;
@@ -318,7 +329,26 @@ GfxPattern *GfxResources::lookupPattern(const char *name) {
return NULL;
}
-GBool GfxResources::lookupGState(const char *name, Object *obj) {
+GfxShading *GfxResources::lookupShading(char *name) {
+ GfxResources *resPtr;
+ GfxShading *shading;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->shadingDict.isDict()) {
+ if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
+ shading = GfxShading::parse(&obj);
+ obj.free();
+ return shading;
+ }
+ obj.free();
+ }
+ }
+ error(-1, "Unknown shading '%s'", name);
+ return NULL;
+}
+
+GBool GfxResources::lookupGState(char *name, Object *obj) {
GfxResources *resPtr;
for (resPtr = this; resPtr; resPtr = resPtr->next) {
@@ -337,18 +367,20 @@ GBool GfxResources::lookupGState(const char *name, Object *obj) {
// Gfx
//------------------------------------------------------------------------
-Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict,
- double dpi, double x1, double y1, double x2, double y2, GBool crop,
- double cropX1, double cropY1, double cropX2, double cropY2,
- int rotate) {
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+ GBool printCommandsA) {
int i;
+ xref = xrefA;
+ printCommands = printCommandsA;
+
// start the resource stack
- res = new GfxResources(resDict, NULL);
+ res = new GfxResources(xref, resDict, NULL);
// initialize
- out = out1;
- state = new GfxState(dpi, x1, y1, x2, y2, rotate, out->upsideDown());
+ out = outA;
+ state = new GfxState(dpi, box, rotate, out->upsideDown());
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
@@ -361,11 +393,12 @@ Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict,
// set crop box
if (crop) {
- state->moveTo(cropX1, cropY1);
- state->lineTo(cropX2, cropY1);
- state->lineTo(cropX2, cropY2);
- state->lineTo(cropX1, cropY2);
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
state->closePath();
+ state->clip();
out->clip(state);
state->clearPath();
}
@@ -406,7 +439,7 @@ void Gfx::display(Object *obj, GBool topLevel) {
error(-1, "Weird page contents");
return;
}
- parser = new Parser(new Lexer(obj));
+ parser = new Parser(xref, new Lexer(xref, obj));
go(topLevel);
delete parser;
parser = NULL;
@@ -433,6 +466,7 @@ void Gfx::go(GBool topLevel) {
args[i].print(stdout);
}
printf("\n");
+ fflush(stdout);
}
execOp(&obj, args, numArgs);
obj.free();
@@ -457,6 +491,7 @@ void Gfx::go(GBool topLevel) {
printf("throwing away arg: ");
obj.print(stdout);
printf("\n");
+ fflush(stdout);
}
obj.free();
}
@@ -476,6 +511,7 @@ void Gfx::go(GBool topLevel) {
args[i].print(stdout);
}
printf("\n");
+ fflush(stdout);
}
for (i = 0; i < numArgs; ++i)
args[i].free();
@@ -485,16 +521,11 @@ void Gfx::go(GBool topLevel) {
if (topLevel && numCmds > 0) {
out->dump();
}
-
- // clean up
- if (printCommands) {
- fflush(stdout);
- }
}
void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
Operator *op;
- const char *name;
+ char *name;
int i;
// find operator
@@ -531,7 +562,7 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
(this->*op->func)(args, numArgs);
}
-Operator *Gfx::findOp(const char *name) {
+Operator *Gfx::findOp(char *name) {
int a, b, m, cmp;
a = -1;
@@ -576,17 +607,11 @@ int Gfx::getPos() {
//------------------------------------------------------------------------
void Gfx::opSave(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
out->saveState(state);
state = state->save();
}
void Gfx::opRestore(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
state = state->restore();
out->restoreState(state);
@@ -598,8 +623,6 @@ void Gfx::opRestore(Object args[], int numArgs) {
}
void Gfx::opConcat(Object args[], int numArgs) {
- (void)numArgs;
-
state->concatCTM(args[0].getNum(), args[1].getNum(),
args[2].getNum(), args[3].getNum(),
args[4].getNum(), args[5].getNum());
@@ -616,8 +639,6 @@ void Gfx::opSetDash(Object args[], int numArgs) {
double *dash;
int i;
- (void)numArgs;
-
a = args[0].getArray();
length = a->getLength();
if (length == 0) {
@@ -778,7 +799,7 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
if (colorSpace) {
state->setFillColorSpace(colorSpace);
} else {
- error(getPos(), "Bad color space");
+ error(getPos(), "Bad color space (fill)");
}
for (i = 0; i < gfxColorMaxComps; ++i) {
color.c[i] = 0;
@@ -804,7 +825,7 @@ void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
if (colorSpace) {
state->setStrokeColorSpace(colorSpace);
} else {
- error(getPos(), "Bad color space");
+ error(getPos(), "Bad color space (stroke)");
}
for (i = 0; i < gfxColorMaxComps; ++i) {
color.c[i] = 0;
@@ -906,14 +927,10 @@ void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opMoveTo(Object args[], int numArgs) {
- (void)numArgs;
-
state->moveTo(args[0].getNum(), args[1].getNum());
}
void Gfx::opLineTo(Object args[], int numArgs) {
- (void)numArgs;
-
if (!state->isCurPt()) {
error(getPos(), "No current point in lineto");
return;
@@ -924,8 +941,6 @@ void Gfx::opLineTo(Object args[], int numArgs) {
void Gfx::opCurveTo(Object args[], int numArgs) {
double x1, y1, x2, y2, x3, y3;
- (void)numArgs;
-
if (!state->isCurPt()) {
error(getPos(), "No current point in curveto");
return;
@@ -942,8 +957,6 @@ void Gfx::opCurveTo(Object args[], int numArgs) {
void Gfx::opCurveTo1(Object args[], int numArgs) {
double x1, y1, x2, y2, x3, y3;
- (void)numArgs;
-
if (!state->isCurPt()) {
error(getPos(), "No current point in curveto1");
return;
@@ -960,8 +973,6 @@ void Gfx::opCurveTo1(Object args[], int numArgs) {
void Gfx::opCurveTo2(Object args[], int numArgs) {
double x1, y1, x2, y2, x3, y3;
- (void)numArgs;
-
if (!state->isCurPt()) {
error(getPos(), "No current point in curveto2");
return;
@@ -978,8 +989,6 @@ void Gfx::opCurveTo2(Object args[], int numArgs) {
void Gfx::opRectangle(Object args[], int numArgs) {
double x, y, w, h;
- (void)numArgs;
-
x = args[0].getNum();
y = args[1].getNum();
w = args[2].getNum();
@@ -992,9 +1001,6 @@ void Gfx::opRectangle(Object args[], int numArgs) {
}
void Gfx::opClosePath(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isPath()) {
error(getPos(), "No current point in closepath");
return;
@@ -1007,16 +1013,10 @@ void Gfx::opClosePath(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opEndPath(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
doEndPath();
}
void Gfx::opStroke(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in stroke");
return;
@@ -1027,9 +1027,6 @@ void Gfx::opStroke(Object args[], int numArgs) {
}
void Gfx::opCloseStroke(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in closepath/stroke");
return;
@@ -1042,9 +1039,6 @@ void Gfx::opCloseStroke(Object args[], int numArgs) {
}
void Gfx::opFill(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in fill");
return;
@@ -1060,9 +1054,6 @@ void Gfx::opFill(Object args[], int numArgs) {
}
void Gfx::opEOFill(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in eofill");
return;
@@ -1078,9 +1069,6 @@ void Gfx::opEOFill(Object args[], int numArgs) {
}
void Gfx::opFillStroke(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in fill/stroke");
return;
@@ -1097,9 +1085,6 @@ void Gfx::opFillStroke(Object args[], int numArgs) {
}
void Gfx::opCloseFillStroke(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in closepath/fill/stroke");
return;
@@ -1117,9 +1102,6 @@ void Gfx::opCloseFillStroke(Object args[], int numArgs) {
}
void Gfx::opEOFillStroke(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in eofill/stroke");
return;
@@ -1136,9 +1118,6 @@ void Gfx::opEOFillStroke(Object args[], int numArgs) {
}
void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (!state->isCurPt()) {
//error(getPos(), "No path in closepath/eofill/stroke");
return;
@@ -1155,25 +1134,19 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
doEndPath();
}
-void Gfx::opShFill(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-}
-
void Gfx::doPatternFill(GBool eoFill) {
GfxPatternColorSpace *patCS;
GfxPattern *pattern;
GfxTilingPattern *tPat;
GfxColorSpace *cs;
- GfxPath *path;
- GfxSubpath *subpath;
double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double cxMin, cyMin, cxMax, cyMax;
int xi0, yi0, xi1, yi1, xi, yi;
double *ctm, *btm, *ptm;
- double m[6], ictm[6], m1[6], im[6];
+ double m[6], ictm[6], m1[6], im[6], imb[6];
double det;
double xstep, ystep;
- int i, j;
+ int i;
// get color space
patCS = (GfxPatternColorSpace *)state->getFillColorSpace();
@@ -1223,33 +1196,14 @@ void Gfx::doPatternFill(GBool eoFill) {
im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
- // compute bounding box of current path, in pattern space
- xMin = xMax = yMin = yMax = 0; // make gcc happy
- path = state->getPath();
- for (i = 0; i < path->getNumSubpaths(); ++i) {
- subpath = path->getSubpath(i);
- for (j = 0; j < subpath->getNumPoints(); ++j) {
- x = subpath->getX(j);
- y = subpath->getY(j);
- x1 = x * im[0] + y * im[2] + im[4];
- y1 = x * im[1] + y * im[3] + im[5];
- if (i == 0 && j == 0) {
- xMin = xMax = x1;
- yMin = yMax = y1;
- } else {
- if (x1 < xMin) {
- xMin = x1;
- } else if (x1 > xMax) {
- xMax = x1;
- }
- if (y1 < yMin) {
- yMin = y1;
- } else if (y1 > yMax) {
- yMax = y1;
- }
- }
- }
- }
+ // construct a (base space) -> (pattern space) transform matrix
+ det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
+ imb[0] = m1[3] * det;
+ imb[1] = -m1[1] * det;
+ imb[2] = -m1[2] * det;
+ imb[3] = m1[0] * det;
+ imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det;
+ imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
// save current graphics state
out->saveState(state);
@@ -1265,6 +1219,7 @@ void Gfx::doPatternFill(GBool eoFill) {
out->updateFillColor(state);
// clip to current path
+ state->clip();
if (eoFill) {
out->eoClip(state);
} else {
@@ -1272,6 +1227,47 @@ void Gfx::doPatternFill(GBool eoFill) {
}
state->clearPath();
+ // transform clip region bbox to pattern space
+ state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
+ xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
+ yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
+ x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+
// draw the pattern
//~ this should treat negative steps differently -- start at right/top
//~ edge instead of left/bottom (?)
@@ -1300,12 +1296,335 @@ void Gfx::doPatternFill(GBool eoFill) {
out->restoreState(state);
}
+void Gfx::opShFill(Object args[], int numArgs) {
+ GfxShading *shading;
+ double xMin, yMin, xMax, yMax;
+
+ if (!(shading = res->lookupShading(args[0].getName()))) {
+ return;
+ }
+
+ // save current graphics state
+ out->saveState(state);
+ state = state->save();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ }
+
+ // restore graphics state
+ state = state->restore();
+ out->restoreState(state);
+
+ delete shading;
+}
+
+void Gfx::doAxialShFill(GfxAxialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1;
+ double det;
+ double *ctm;
+ double ictm[6];
+ double dx, dy, mul;
+ double tMin, tMax, t, tx, ty;
+ double s[4], sMin, sMax, tmp;
+ double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
+ double t0, t1, tt;
+ double ta[axialMaxSplits + 1];
+ int next[axialMaxSplits + 1];
+ GfxColor color0, color1;
+ int nComps;
+ int i, j, k, kk;
+
+ // get clip region bbox and transform to current user space
+ state->getClipBBox(&x0, &y0, &x1, &y1);
+ ctm = state->getCTM();
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ xMin = xMax = x0 * ictm[0] + y0 * ictm[2] + ictm[4];
+ yMin = yMax = x0 * ictm[1] + y0 * ictm[3] + ictm[5];
+ tx = x0 * ictm[0] + y1 * ictm[2] + ictm[4];
+ ty = x0 * ictm[1] + y1 * ictm[3] + ictm[5];
+ if (tx < xMin) {
+ xMin = tx;
+ } else if (tx > xMax) {
+ xMax = tx;
+ }
+ if (ty < yMin) {
+ yMin = ty;
+ } else if (ty > yMax) {
+ yMax = ty;
+ }
+ tx = x1 * ictm[0] + y0 * ictm[2] + ictm[4];
+ ty = x1 * ictm[1] + y0 * ictm[3] + ictm[5];
+ if (tx < xMin) {
+ xMin = tx;
+ } else if (tx > xMax) {
+ xMax = tx;
+ }
+ if (ty < yMin) {
+ yMin = ty;
+ } else if (ty > yMax) {
+ yMax = ty;
+ }
+ tx = x1 * ictm[0] + y1 * ictm[2] + ictm[4];
+ ty = x1 * ictm[1] + y1 * ictm[3] + ictm[5];
+ if (tx < xMin) {
+ xMin = tx;
+ } else if (tx > xMax) {
+ xMax = tx;
+ }
+ if (ty < yMin) {
+ yMin = ty;
+ } else if (ty > yMax) {
+ yMax = ty;
+ }
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ mul = 1 / (dx * dx + dy * dy);
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
+ }
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Traverse the t axis and do the shading.
+ //
+ // For each point (tx, ty) on the t axis, consider a line through
+ // that point perpendicular to the t axis:
+ //
+ // x(s) = tx + s * -dy --> s = (x - tx) / -dy
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
+ //
+ // Then look at the intersection of this line with the bounding box
+ // (xMin, yMin, xMax, yMax). In the general case, there are four
+ // intersection points:
+ //
+ // s0 = (xMin - tx) / -dy
+ // s1 = (xMax - tx) / -dy
+ // s2 = (yMin - ty) / dx
+ // s3 = (yMax - ty) / dx
+ //
+ // and we want the middle two s values.
+ //
+ // In the case where dx = 0, take s0 and s1; in the case where dy =
+ // 0, take s2 and s3.
+ //
+ // Each filled polygon is bounded by two of these line segments
+ // perpdendicular to the t axis.
+ //
+ // The t axis is bisected into smaller regions until the color
+ // difference across a region is small enough, and then the region
+ // is painted with a single color.
+
+ // set up
+ nComps = shading->getColorSpace()->getNComps();
+ ta[0] = tMin;
+ ta[axialMaxSplits] = tMax;
+ next[0] = axialMaxSplits;
+
+ // compute the color at t = tMin
+ if (tMin < 0) {
+ tt = t0;
+ } else if (tMin > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * tMin;
+ }
+ shading->getColor(tt, &color0);
+
+ // compute the coordinates of the point on the t axis at t = tMin;
+ // then compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + tMin * dx;
+ ty = y0 + tMin * dy;
+ if (dx == 0 && dy == 0) {
+ sMin = sMax = 0;
+ } if (dx == 0) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dy == 0) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux0 = tx - sMin * dy;
+ uy0 = ty + sMin * dx;
+ vx0 = tx - sMax * dy;
+ vy0 = ty + sMax * dx;
+
+ i = 0;
+ while (i < axialMaxSplits) {
+
+ // bisect until color difference is small enough or we hit the
+ // bisection limit
+ j = next[i];
+ while (j > i + 1) {
+ if (ta[j] < 0) {
+ tt = t0;
+ } else if (ta[j] > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * ta[j];
+ }
+ shading->getColor(tt, &color1);
+ for (k = 0; k < nComps; ++k) {
+ if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps) {
+ break;
+ }
+ k = (i + j) / 2;
+ ta[k] = 0.5 * (ta[i] + ta[j]);
+ next[i] = k;
+ next[k] = j;
+ j = k;
+ }
+
+ // use the average of the colors of the two sides of the region
+ for (k = 0; k < nComps; ++k) {
+ color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]);
+ }
+
+ // compute the coordinates of the point on the t axis; then
+ // compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + ta[j] * dx;
+ ty = y0 + ta[j] * dy;
+ if (dx == 0 && dy == 0) {
+ sMin = sMax = 0;
+ } if (dx == 0) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dy == 0) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux1 = tx - sMin * dy;
+ uy1 = ty + sMin * dx;
+ vx1 = tx - sMax * dy;
+ vy1 = ty + sMax * dx;
+
+ // set the color
+ state->setFillColor(&color0);
+ out->updateFillColor(state);
+
+ // fill the region
+ state->moveTo(ux0, uy0);
+ state->lineTo(vx0, vy0);
+ state->lineTo(vx1, vy1);
+ state->lineTo(ux1, uy1);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // set up for next region
+ ux0 = ux1;
+ uy0 = uy1;
+ vx0 = vx1;
+ vy0 = vy1;
+ color0 = color1;
+ i = next[i];
+ }
+}
+
void Gfx::doEndPath() {
- if (state->isPath()) {
- if (clip == clipNormal)
+ if (state->isPath() && clip != clipNone) {
+ state->clip();
+ if (clip == clipNormal) {
out->clip(state);
- else if (clip == clipEO)
+ } else {
out->eoClip(state);
+ }
}
clip = clipNone;
state->clearPath();
@@ -1316,16 +1635,10 @@ void Gfx::doEndPath() {
//------------------------------------------------------------------------
void Gfx::opClip(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
clip = clipNormal;
}
void Gfx::opEOClip(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
clip = clipEO;
}
@@ -1334,9 +1647,6 @@ void Gfx::opEOClip(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opBeginText(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
state->setTextMat(1, 0, 0, 1, 0, 0);
state->textMoveTo(0, 0);
out->updateTextMat(state);
@@ -1345,8 +1655,6 @@ void Gfx::opBeginText(Object args[], int numArgs) {
}
void Gfx::opEndText(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
}
//------------------------------------------------------------------------
@@ -1354,9 +1662,6 @@ void Gfx::opEndText(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opSetCharSpacing(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
state->setCharSpace(args[0].getNum());
out->updateCharSpace(state);
}
@@ -1371,43 +1676,35 @@ void Gfx::opSetFont(Object args[], int numArgs) {
printf(" font: '%s' %g\n",
font->getName() ? font->getName()->getCString() : "???",
args[1].getNum());
+ fflush(stdout);
}
state->setFont(font, args[1].getNum());
fontChanged = gTrue;
}
void Gfx::opSetTextLeading(Object args[], int numArgs) {
- (void)numArgs;
-
state->setLeading(args[0].getNum());
}
void Gfx::opSetTextRender(Object args[], int numArgs) {
- (void)numArgs;
-
state->setRender(args[0].getInt());
out->updateRender(state);
}
void Gfx::opSetTextRise(Object args[], int numArgs) {
- (void)numArgs;
-
state->setRise(args[0].getNum());
out->updateRise(state);
}
void Gfx::opSetWordSpacing(Object args[], int numArgs) {
- (void)numArgs;
-
state->setWordSpace(args[0].getNum());
out->updateWordSpace(state);
}
void Gfx::opSetHorizScaling(Object args[], int numArgs) {
- (void)numArgs;
-
state->setHorizScaling(args[0].getNum());
out->updateHorizScaling(state);
+ fontChanged = gTrue;
}
//------------------------------------------------------------------------
@@ -1417,8 +1714,6 @@ void Gfx::opSetHorizScaling(Object args[], int numArgs) {
void Gfx::opTextMove(Object args[], int numArgs) {
double tx, ty;
- (void)numArgs;
-
tx = state->getLineX() + args[0].getNum();
ty = state->getLineY() + args[1].getNum();
state->textMoveTo(tx, ty);
@@ -1428,8 +1723,6 @@ void Gfx::opTextMove(Object args[], int numArgs) {
void Gfx::opTextMoveSet(Object args[], int numArgs) {
double tx, ty;
- (void)numArgs;
-
tx = state->getLineX() + args[0].getNum();
ty = args[1].getNum();
state->setLeading(-ty);
@@ -1439,8 +1732,6 @@ void Gfx::opTextMoveSet(Object args[], int numArgs) {
}
void Gfx::opSetTextMatrix(Object args[], int numArgs) {
- (void)numArgs;
-
state->setTextMat(args[0].getNum(), args[1].getNum(),
args[2].getNum(), args[3].getNum(),
args[4].getNum(), args[5].getNum());
@@ -1453,9 +1744,6 @@ void Gfx::opSetTextMatrix(Object args[], int numArgs) {
void Gfx::opTextNextLine(Object args[], int numArgs) {
double tx, ty;
- (void)args;
- (void)numArgs;
-
tx = state->getLineX();
ty = state->getLineY() - state->getLeading();
state->textMoveTo(tx, ty);
@@ -1467,8 +1755,6 @@ void Gfx::opTextNextLine(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opShowText(Object args[], int numArgs) {
- (void)numArgs;
-
if (!state->getFont()) {
error(getPos(), "No font in show");
return;
@@ -1479,8 +1765,6 @@ void Gfx::opShowText(Object args[], int numArgs) {
void Gfx::opMoveShowText(Object args[], int numArgs) {
double tx, ty;
- (void)numArgs;
-
if (!state->getFont()) {
error(getPos(), "No font in move/show");
return;
@@ -1495,8 +1779,6 @@ void Gfx::opMoveShowText(Object args[], int numArgs) {
void Gfx::opMoveSetShowText(Object args[], int numArgs) {
double tx, ty;
- (void)numArgs;
-
if (!state->getFont()) {
error(getPos(), "No font in move/set/show");
return;
@@ -1517,8 +1799,6 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) {
Object obj;
int i;
- (void)numArgs;
-
if (!state->getFont()) {
error(getPos(), "No font in show/space");
return;
@@ -1547,7 +1827,7 @@ void Gfx::doShowText(GString *s) {
GString *s16;
char s16a[2];
int m, n;
-#if 0 //~type3
+#if 1 //~type3
double dx, dy, width, height, w, h, x, y;
double oldCTM[6], newCTM[6];
double *mat;
@@ -1555,8 +1835,9 @@ void Gfx::doShowText(GString *s) {
Parser *oldParser;
int i;
#else
- double dx, dy, width, height, w, h, sWidth, sHeight;
+ double dx, dy, width, height, w, h;
#endif
+ double sWidth, sHeight;
if (fontChanged) {
out->updateFont(state);
@@ -1580,12 +1861,12 @@ void Gfx::doShowText(GString *s) {
while (n > 0) {
m = getNextChar16(enc, p, &c16);
if (enc->wMode == 0) {
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth16(c16) +
+ width = state->getFontSize() * font->getWidth16(c16) +
state->getCharSpace();
- if (c16 == ' ') {
+ if (m == 1 && c16 == ' ') {
width += state->getWordSpace();
}
+ width *= state->getHorizScaling();
height = 0;
} else {
width = 0;
@@ -1616,7 +1897,7 @@ void Gfx::doShowText(GString *s) {
//----- 8-bit font
} else {
-#if 0 //~type3
+#if 1 //~type3
//~ also check out->renderType3()
if (font->getType() == fontType3) {
out->beginString(state, s);
@@ -1644,6 +1925,8 @@ void Gfx::doShowText(GString *s) {
c8 = *p;
font->getCharProc(c8, &charProc);
state->transform(state->getCurX() + dx, state->getCurY() + dy, &x, &y);
+ out->saveState(state);
+ state = state->save();
state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
//~ out->updateCTM(???)
if (charProc.isStream()) {
@@ -1651,16 +1934,15 @@ void Gfx::doShowText(GString *s) {
} else {
error(getPos(), "Missing or bad Type3 CharProc entry");
}
- state->setCTM(oldCTM[0], oldCTM[1], oldCTM[2],
- oldCTM[3], oldCTM[4], oldCTM[5]);
- //~ out->updateCTM(???) - use gsave/grestore instead?
+ state = state->restore();
+ out->restoreState(state);
charProc.free();
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(c8) +
+ width = state->getFontSize() * font->getWidth(c8) +
state->getCharSpace();
if (c8 == ' ') {
width += state->getWordSpace();
}
+ width *= state->getHorizScaling();
state->textShift(width);
}
parser = oldParser;
@@ -1672,11 +1954,12 @@ void Gfx::doShowText(GString *s) {
state->textTransformDelta(0, state->getRise(), &dx, &dy);
for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
c8 = *p;
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(c8) +
+ width = state->getFontSize() * font->getWidth(c8) +
state->getCharSpace();
- if (c8 == ' ')
+ if (c8 == ' ') {
width += state->getWordSpace();
+ }
+ width *= state->getHorizScaling();
state->textTransformDelta(width, 0, &w, &h);
out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy,
w, h, c8);
@@ -1685,13 +1968,14 @@ void Gfx::doShowText(GString *s) {
out->endString(state);
} else {
out->drawString(state, s);
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(s) +
+ width = state->getFontSize() * font->getWidth(s) +
s->getLength() * state->getCharSpace();
for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
- if (*p == ' ')
+ if (*p == ' ') {
width += state->getWordSpace();
+ }
}
+ width *= state->getHorizScaling();
state->textShift(width);
}
}
@@ -1772,13 +2056,17 @@ void Gfx::opXObject(Object args[], int numArgs) {
void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
Dict *dict;
- Object obj1, obj2;
int width, height;
int bits;
GBool mask;
+ GBool invert;
GfxColorSpace *colorSpace;
GfxImageColorMap *colorMap;
- GBool invert;
+ Object maskObj;
+ GBool haveMask;
+ int maskColors[2*gfxColorMaxComps];
+ Object obj1, obj2;
+ int i;
// get stream dict
dict = str->getDict();
@@ -1886,10 +2174,25 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
goto err1;
}
+ // get the mask
+ haveMask = gFalse;
+ dict->lookup("Mask", &maskObj);
+ if (maskObj.isArray()) {
+ for (i = 0; i < maskObj.arrayGetLength(); ++i) {
+ maskObj.arrayGet(i, &obj1);
+ maskColors[i] = obj1.getInt();
+ obj1.free();
+ }
+ haveMask = gTrue;
+ }
+
// draw it
- out->drawImage(state, ref, str, width, height, colorMap, inlineImg);
+ out->drawImage(state, ref, str, width, height, colorMap,
+ haveMask ? maskColors : (int *)NULL, inlineImg);
delete colorMap;
str->close();
+
+ maskObj.free();
}
return;
@@ -1951,7 +2254,7 @@ void Gfx::doForm(Object *str) {
// get resources
dict->lookup("Resources", &resObj);
- resDict = resObj.isDict() ? resObj.getDict() : NULL;
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
// draw it
doForm1(str, resDict, m, bbox);
@@ -2013,7 +2316,7 @@ void Gfx::doWidgetForm(Object *str, double xMin, double yMin,
// get resources
dict->lookup("Resources", &resObj);
- resDict = resObj.isDict() ? resObj.getDict() : NULL;
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
// draw it
doForm1(str, resDict, m, bbox);
@@ -2029,7 +2332,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
int i;
// push new resources on stack
- res = new GfxResources(resDict, res);
+ res = new GfxResources(xref, resDict, res);
// save current graphics state
out->saveState(state);
@@ -2056,6 +2359,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
state->lineTo(bbox[2], bbox[3]);
state->lineTo(bbox[0], bbox[3]);
state->closePath();
+ state->clip();
out->clip(state);
state->clearPath();
@@ -2090,9 +2394,6 @@ void Gfx::opBeginImage(Object args[], int numArgs) {
Stream *str;
int c1, c2;
- (void)args;
- (void)numArgs;
-
// build dict/stream
str = buildImageStream();
@@ -2114,11 +2415,11 @@ void Gfx::opBeginImage(Object args[], int numArgs) {
Stream *Gfx::buildImageStream() {
Object dict;
Object obj;
- const char *key;
+ char *key;
Stream *str;
// build dictionary
- dict.initDict();
+ dict.initDict(xref);
parser->getObj(&obj);
while (!obj.isCmd("ID") && !obj.isEOF()) {
if (!obj.isName()) {
@@ -2147,16 +2448,10 @@ Stream *Gfx::buildImageStream() {
}
void Gfx::opImageData(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
error(getPos(), "Internal: got 'ID' operator");
}
void Gfx::opEndImage(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
error(getPos(), "Internal: got 'EI' operator");
}
@@ -2165,17 +2460,11 @@ void Gfx::opEndImage(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opSetCharWidth(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
- error(getPos(), "Encountered 'd0' operator in content stream");
+// error(getPos(), "Encountered 'd0' operator in content stream");
}
void Gfx::opSetCacheDevice(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
- error(getPos(), "Encountered 'd1' operator in content stream");
+// error(getPos(), "Encountered 'd1' operator in content stream");
}
//------------------------------------------------------------------------
@@ -2183,16 +2472,10 @@ void Gfx::opSetCacheDevice(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
++ignoreUndef;
}
void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
-
if (ignoreUndef > 0)
--ignoreUndef;
}
@@ -2202,28 +2485,24 @@ void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
//------------------------------------------------------------------------
void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
- (void)numArgs;
-
if (printCommands) {
printf(" marked content: %s ", args[0].getName());
if (numArgs == 2)
args[2].print(stdout);
printf("\n");
+ fflush(stdout);
}
}
void Gfx::opEndMarkedContent(Object args[], int numArgs) {
- (void)args;
- (void)numArgs;
}
void Gfx::opMarkPoint(Object args[], int numArgs) {
- (void)numArgs;
-
if (printCommands) {
printf(" mark point: %s ", args[0].getName());
if (numArgs == 2)
args[2].print(stdout);
printf("\n");
+ fflush(stdout);
}
}
diff --git a/pdftops/Gfx.h b/pdftops/Gfx.h
index 011fbfcd14..24e124697a 100644
--- a/pdftops/Gfx.h
+++ b/pdftops/Gfx.h
@@ -16,6 +16,7 @@
#include "gtypes.h"
class GString;
+class XRef;
class Array;
class Stream;
class Parser;
@@ -25,8 +26,11 @@ class GfxFontDict;
class GfxFont;
struct GfxFontEncoding16;
class GfxPattern;
+class GfxShading;
+class GfxAxialShading;
class GfxState;
class Gfx;
+struct PDFRectangle;
//------------------------------------------------------------------------
// Gfx
@@ -62,15 +66,16 @@ struct Operator {
class GfxResources {
public:
- GfxResources(Dict *resDict, GfxResources *next);
+ GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA);
~GfxResources();
- GfxFont *lookupFont(const char *name);
- GBool lookupXObject(const char *name, Object *obj);
- GBool lookupXObjectNF(const char *name, Object *obj);
- void lookupColorSpace(const char *name, Object *obj);
- GfxPattern *lookupPattern(const char *name);
- GBool lookupGState(const char *name, Object *obj);
+ GfxFont *lookupFont(char *name);
+ GBool lookupXObject(char *name, Object *obj);
+ GBool lookupXObjectNF(char *name, Object *obj);
+ void lookupColorSpace(char *name, Object *obj);
+ GfxPattern *lookupPattern(char *name);
+ GfxShading *lookupShading(char *name);
+ GBool lookupGState(char *name, Object *obj);
GfxResources *getNext() { return next; }
@@ -80,6 +85,7 @@ private:
Object xObjDict;
Object colorSpaceDict;
Object patternDict;
+ Object shadingDict;
Object gStateDict;
GfxResources *next;
};
@@ -88,10 +94,9 @@ class Gfx {
public:
// Constructor for regular output.
- Gfx(OutputDev *out1, int pageNum, Dict *resDict,
- double dpi, double x1, double y1, double x2, double y2, GBool crop,
- double cropX1, double cropY1, double cropX2, double cropY2,
- int rotate);
+ Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
+ PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+ GBool printCommandsA);
// Destructor.
~Gfx();
@@ -104,7 +109,9 @@ public:
private:
+ XRef *xref; // the xref table for this PDF file
OutputDev *out; // output device
+ GBool printCommands; // print the drawing commands (for debugging)
GfxResources *res; // resource stack
GfxState *state; // current graphics state
@@ -120,7 +127,7 @@ private:
void go(GBool topLevel);
void execOp(Object *cmd, Object args[], int numArgs);
- Operator *findOp(const char *name);
+ Operator *findOp(char *name);
GBool checkArg(Object *arg, TchkType type);
int getPos();
@@ -170,8 +177,9 @@ private:
void opCloseFillStroke(Object args[], int numArgs);
void opEOFillStroke(Object args[], int numArgs);
void opCloseEOFillStroke(Object args[], int numArgs);
- void opShFill(Object args[], int numArgs);
void doPatternFill(GBool eoFill);
+ void opShFill(Object args[], int numArgs);
+ void doAxialShFill(GfxAxialShading *shading);
void doEndPath();
// path clipping operators
diff --git a/pdftops/GfxFont.cxx b/pdftops/GfxFont.cxx
index 413796f2d9..96b802e146 100644
--- a/pdftops/GfxFont.cxx
+++ b/pdftops/GfxFont.cxx
@@ -40,12 +40,10 @@
//------------------------------------------------------------------------
-#if defined(JAPANESE_SUPPORT) || defined(CHINESE_GB_SUPPORT) || defined(CHINESE_CNS_SUPPORT)
extern "C" {
-static int cmpWidthExcep(const void *w1, const void *w2);
-static int cmpWidthExcepV(const void *w1, const void *w2);
+static int CDECL cmpWidthExcep(const void *w1, const void *w2);
+static int CDECL cmpWidthExcepV(const void *w1, const void *w2);
}
-#endif /* JAPANESE_SUPPORT || CHINESE_GB_SUPPORT || CHINESE_CNS_SUPPORT */
//------------------------------------------------------------------------
@@ -68,16 +66,16 @@ static Gushort *defCharWidths[12] = {
// GfxFont
//------------------------------------------------------------------------
-GfxFont::GfxFont(const char *tag1, Ref id1, Dict *fontDict) {
+GfxFont::GfxFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
BuiltinFont *builtinFont;
Object obj1, obj2, obj3, obj4;
int missingWidth;
- const char *name2, *p;
+ char *name2, *p;
int i;
// get font tag and ID
- tag = new GString(tag1);
- id = id1;
+ tag = new GString(tagA);
+ id = idA;
// get font type
type = fontUnknownType;
@@ -106,7 +104,7 @@ GfxFont::GfxFont(const char *tag1, Ref id1, Dict *fontDict) {
// without embedding them, so munge the names into the equivalent
// PostScript names. This is a kludge -- it would be nice if Adobe
// followed their own spec.
- if (type == fontTrueType) {
+ if (type == fontTrueType && name) {
p = name->getCString();
name2 = NULL;
if (!strncmp(p, "Arial", 5)) {
@@ -160,12 +158,39 @@ GfxFont::GfxFont(const char *tag1, Ref id1, Dict *fontDict) {
// assume Times-Roman by default (for substitution purposes)
flags = fontSerif;
+ // default ascent/descent values
+ if (builtinFont) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ } else {
+ ascent = 0.95;
+ descent = -0.35;
+ }
+
// get info from font descriptor
embFontName = NULL;
embFontID.num = -1;
embFontID.gen = -1;
missingWidth = 0;
- fontDict->lookup("FontDescriptor", &obj1);
+ if (type == fontType0) {
+ fontDict->lookup("DescendantFonts", &obj2);
+ if (obj2.isArray()) {
+ obj2.arrayGet(0, &obj3);
+ if (obj3.isDict()) {
+ obj3.dictLookup("FontDescriptor", &obj1);
+ } else {
+ error(-1, "Bad descendant font in Type 0 font");
+ obj1.initNull();
+ }
+ obj3.free();
+ } else {
+ error(-1, "Missing DescendantFonts entry in Type 0 font");
+ obj1.initNull();
+ }
+ obj2.free();
+ } else {
+ fontDict->lookup("FontDescriptor", &obj1);
+ }
if (obj1.isDict()) {
// get flags
@@ -197,7 +222,7 @@ GfxFont::GfxFont(const char *tag1, Ref id1, Dict *fontDict) {
obj1.dictLookupNF("FontFile3", &obj2);
if (obj2.isRef()) {
embFontID = obj2.getRef();
- obj2.fetch(&obj3);
+ obj2.fetch(xref, &obj3);
if (obj3.isStream()) {
obj3.streamGetDict()->lookup("Subtype", &obj4);
if (obj4.isName("Type1"))
@@ -223,6 +248,30 @@ GfxFont::GfxFont(const char *tag1, Ref id1, Dict *fontDict) {
missingWidth = obj2.getInt();
}
obj2.free();
+
+ // get Ascent and Descent
+ obj1.dictLookup("Ascent", &obj2);
+ if (obj2.isNum()) {
+ ascent = 0.001 * obj2.getNum();
+ }
+ obj2.free();
+ obj1.dictLookup("Descent", &obj2);
+ if (obj2.isNum()) {
+ descent = 0.001 * obj2.getNum();
+ }
+ obj2.free();
+
+ // font FontBBox
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
+ for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ fontBBox[i] = obj3.getNum();
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
}
obj1.free();
@@ -256,7 +305,7 @@ GfxFont::GfxFont(const char *tag1, Ref id1, Dict *fontDict) {
if (type == fontType0) {
getType0EncAndWidths(fontDict);
} else {
- getEncAndWidths(fontDict, builtinFont, missingWidth);
+ getEncAndWidths(xref, fontDict, builtinFont, missingWidth);
}
}
@@ -390,10 +439,10 @@ Object *GfxFont::getCharProc(int code, Object *proc) {
return proc;
}
-void GfxFont::getEncAndWidths(Dict *fontDict, BuiltinFont *builtinFont,
- int missingWidth) {
+void GfxFont::getEncAndWidths(XRef *xref, Dict *fontDict,
+ BuiltinFont *builtinFont, int missingWidth) {
Object obj1, obj2, obj3;
- const char *buf;
+ char *buf;
int len;
FontFile *fontFile;
int code, i;
@@ -433,26 +482,31 @@ void GfxFont::getEncAndWidths(Dict *fontDict, BuiltinFont *builtinFont,
obj1.free();
// check embedded or external font file for base encoding
- if ((type == fontType1 || type == fontType1C) &&
+ if ((type == fontType1 || type == fontType1C || type == fontTrueType) &&
(extFontFile || embFontID.num >= 0)) {
- if (extFontFile)
+ if (extFontFile) {
buf = readExtFontFile(&len);
- else
- buf = readEmbFontFile(&len);
+ } else {
+ buf = readEmbFontFile(xref, &len);
+ }
if (buf) {
- if (type == fontType1)
+ if (type == fontType1) {
fontFile = new Type1FontFile(buf, len);
- else
+ } else if (type == fontType1C) {
fontFile = new Type1CFontFile(buf, len);
+ } else {
+ fontFile = new TrueTypeFontFile(buf, len);
+ }
if (fontFile->getName()) {
if (embFontName)
delete embFontName;
embFontName = new GString(fontFile->getName());
}
- if (!encoding)
+ if (!encoding) {
encoding = fontFile->getEncoding(gTrue);
+ }
delete fontFile;
- gfree((void *)buf);
+ gfree(buf);
}
}
@@ -500,7 +554,7 @@ void GfxFont::getEncAndWidths(Dict *fontDict, BuiltinFont *builtinFont,
}
void GfxFont::findExtFontFile() {
- const char **path;
+ char **path;
FILE *f;
for (path = fontPath; *path; ++path) {
@@ -524,7 +578,7 @@ void GfxFont::findExtFontFile() {
}
}
-const char *GfxFont::readExtFontFile(int *len) {
+char *GfxFont::readExtFontFile(int *len) {
FILE *f;
char *buf;
@@ -542,7 +596,7 @@ const char *GfxFont::readExtFontFile(int *len) {
return buf;
}
-const char *GfxFont::readEmbFontFile(int *len) {
+char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
char *buf;
Object obj1, obj2;
Stream *str;
@@ -550,7 +604,7 @@ const char *GfxFont::readEmbFontFile(int *len) {
int size, i;
obj1.initRef(embFontID.num, embFontID.gen);
- obj1.fetch(&obj2);
+ obj1.fetch(xref, &obj2);
if (!obj2.isStream()) {
error(-1, "Embedded font file is not a stream");
obj2.free();
@@ -584,7 +638,7 @@ void GfxFont::makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
Object obj1, obj2;
int firstChar, lastChar;
int code, code2;
- const char *charName;
+ char *charName;
Gushort *defWidths;
int index;
double mult;
@@ -594,72 +648,73 @@ void GfxFont::makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
widths[code] = missingWidth * 0.001;
}
+ // use widths from font dict, if present
+ fontDict->lookup("FirstChar", &obj1);
+ firstChar = obj1.isInt() ? obj1.getInt() : 0;
+ obj1.free();
+ fontDict->lookup("LastChar", &obj1);
+ lastChar = obj1.isInt() ? obj1.getInt() : 255;
+ obj1.free();
+ if (type == fontType3)
+ mult = fontMat[0];
+ else
+ mult = 0.001;
+ fontDict->lookup("Widths", &obj1);
+ if (obj1.isArray()) {
+ for (code = firstChar; code <= lastChar; ++code) {
+ obj1.arrayGet(code - firstChar, &obj2);
+ if (obj2.isNum())
+ widths[code] = obj2.getNum() * mult;
+ obj2.free();
+ }
+
// use widths from built-in font
- if (builtinEncoding) {
+ } else if (builtinEncoding) {
code2 = 0; // to make gcc happy
for (code = 0; code < 256; ++code) {
if ((charName = encoding->getCharName(code)) &&
- (code2 = builtinEncoding->getCharCode(charName)) >= 0)
+ (code2 = builtinEncoding->getCharCode(charName)) >= 0) {
widths[code] = builtinWidths[code2] * 0.001;
+ } else if (code == 32) {
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ widths[code] = builtinWidths[' '] * 0.001;
+ }
}
- // get widths from font dict
+ // couldn't find widths -- use defaults
} else {
- fontDict->lookup("FirstChar", &obj1);
- firstChar = obj1.isInt() ? obj1.getInt() : 0;
- obj1.free();
- fontDict->lookup("LastChar", &obj1);
- lastChar = obj1.isInt() ? obj1.getInt() : 255;
- obj1.free();
- if (type == fontType3)
- mult = fontMat[0];
- else
- mult = 0.001;
- fontDict->lookup("Widths", &obj1);
- if (obj1.isArray()) {
- for (code = firstChar; code <= lastChar; ++code) {
- obj1.arrayGet(code - firstChar, &obj2);
- if (obj2.isNum())
- widths[code] = obj2.getNum() * mult;
- obj2.free();
- }
- } else {
-
- // couldn't find widths -- use defaults
#if 0 //~
- //~ certain PDF generators apparently don't include widths
- //~ for Arial and TimesNewRoman -- and this error message
- //~ is a nuisance
- error(-1, "No character widths resource for non-builtin font");
+ //~ certain PDF generators apparently don't include widths
+ //~ for Arial and TimesNewRoman -- and this error message
+ //~ is a nuisance
+ error(-1, "No character widths resource for non-builtin font");
#endif
- if (isFixedWidth())
- index = 0;
- else if (isSerif())
- index = 8;
- else
- index = 4;
- if (isBold())
- index += 2;
- if (isItalic())
- index += 1;
- defWidths = defCharWidths[index];
- code2 = 0; // to make gcc happy
- for (code = 0; code < 256; ++code) {
- if ((charName = encoding->getCharName(code)) &&
- (code2 = standardEncoding.getCharCode(charName)) >= 0)
- widths[code] = defWidths[code2] * 0.001;
- }
+ if (isFixedWidth())
+ index = 0;
+ else if (isSerif())
+ index = 8;
+ else
+ index = 4;
+ if (isBold())
+ index += 2;
+ if (isItalic())
+ index += 1;
+ defWidths = defCharWidths[index];
+ code2 = 0; // to make gcc happy
+ for (code = 0; code < 256; ++code) {
+ if ((charName = encoding->getCharName(code)) &&
+ (code2 = standardEncoding.getCharCode(charName)) >= 0)
+ widths[code] = defWidths[code2] * 0.001;
}
- obj1.free();
}
+ obj1.free();
}
void GfxFont::getType0EncAndWidths(Dict *fontDict) {
Object obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8;
-#if defined(JAPANESE_SUPPORT) || defined(CHINESE_GB_SUPPORT) || defined(CHINESE_CNS_SUPPORT)
int excepsSize;
int i, j, k, n;
-#endif /* JAPANESE_SUPPORT || CHINESE_GB_SUPPORT || CHINESE_CNS_SUPPORT */
widths16.exceps = NULL;
widths16.excepsV = NULL;
@@ -713,7 +768,7 @@ void GfxFont::getType0EncAndWidths(Dict *fontDict) {
goto err4;
#endif
} else {
- error(-1, "Uknown Type 0 character set: %s-%s",
+ error(-1, "Unknown Type 0 character set: %s-%s",
obj4.getString()->getCString(), obj5.getString()->getCString());
goto err4;
}
@@ -721,8 +776,6 @@ void GfxFont::getType0EncAndWidths(Dict *fontDict) {
error(-1, "Unknown Type 0 character set");
goto err4;
}
-
-#if defined(JAPANESE_SUPPORT) || defined(CHINESE_GB_SUPPORT) || defined(CHINESE_CNS_SUPPORT)
obj5.free();
obj4.free();
obj3.free();
@@ -914,7 +967,7 @@ void GfxFont::getType0EncAndWidths(Dict *fontDict) {
error(-1, "Bad encoding for Type 0 font");
goto err1;
}
-# if JAPANESE_SUPPORT
+#if JAPANESE_SUPPORT
if (enc16.charSet == font16AdobeJapan12) {
for (i = 0; gfxJapan12Tab[i].name; ++i) {
if (!strcmp(obj1.getName(), gfxJapan12Tab[i].name))
@@ -927,8 +980,8 @@ void GfxFont::getType0EncAndWidths(Dict *fontDict) {
}
enc16.enc = gfxJapan12Tab[i].enc;
}
-# endif
-# if CHINESE_GB_SUPPORT
+#endif
+#if CHINESE_GB_SUPPORT
if (enc16.charSet == font16AdobeGB12) {
for (i = 0; gfxGB12Tab[i].name; ++i) {
if (!strcmp(obj1.getName(), gfxGB12Tab[i].name))
@@ -941,8 +994,8 @@ void GfxFont::getType0EncAndWidths(Dict *fontDict) {
}
enc16.enc = gfxGB12Tab[i].enc;
}
-# endif
-# if CHINESE_CNS_SUPPORT
+#endif
+#if CHINESE_CNS_SUPPORT
if (enc16.charSet == font16AdobeCNS13) {
for (i = 0; gfxCNS13Tab[i].name; ++i) {
if (!strcmp(obj1.getName(), gfxCNS13Tab[i].name))
@@ -955,11 +1008,10 @@ void GfxFont::getType0EncAndWidths(Dict *fontDict) {
}
enc16.enc = gfxCNS13Tab[i].enc;
}
-# endif
+#endif
obj1.free();
return;
-#endif /* JAPANESE_SUPPORT || CHINESE_GB_SUPPORT || CHINESE_CNS_SUPPORT */
err4:
obj5.free();
@@ -975,21 +1027,21 @@ void GfxFont::getType0EncAndWidths(Dict *fontDict) {
makeWidths(fontDict, NULL, NULL, 0);
}
-#if defined(JAPANESE_SUPPORT) || defined(CHINESE_GB_SUPPORT) || defined(CHINESE_CNS_SUPPORT)
-static int cmpWidthExcep(const void *w1, const void *w2) {
+extern "C" {
+static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
return ((GfxFontWidthExcep *)w1)->first - ((GfxFontWidthExcep *)w2)->first;
}
-static int cmpWidthExcepV(const void *w1, const void *w2) {
+static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
return ((GfxFontWidthExcepV *)w1)->first - ((GfxFontWidthExcepV *)w2)->first;
}
-#endif /* JAPANESE_SUPPORT || CHINESE_GB_SUPPORT || CHINESE_CNS_SUPPORT */
+}
//------------------------------------------------------------------------
// GfxFontDict
//------------------------------------------------------------------------
-GfxFontDict::GfxFontDict(Dict *fontDict) {
+GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) {
int i;
Object obj1, obj2;
@@ -997,10 +1049,10 @@ GfxFontDict::GfxFontDict(Dict *fontDict) {
fonts = (GfxFont **)gmalloc(numFonts * sizeof(GfxFont *));
for (i = 0; i < numFonts; ++i) {
fontDict->getValNF(i, &obj1);
- obj1.fetch(&obj2);
+ obj1.fetch(xref, &obj2);
if (obj1.isRef() && obj2.isDict()) {
- fonts[i] = new GfxFont(fontDict->getKey(i), obj1.getRef(),
- obj2.getDict());
+ fonts[i] = new GfxFont(xref, fontDict->getKey(i),
+ obj1.getRef(), obj2.getDict());
} else {
error(-1, "font resource is not a dictionary");
fonts[i] = NULL;
@@ -1018,7 +1070,7 @@ GfxFontDict::~GfxFontDict() {
gfree(fonts);
}
-GfxFont *GfxFontDict::lookup(const char *tag) {
+GfxFont *GfxFontDict::lookup(char *tag) {
int i;
for (i = 0; i < numFonts; ++i) {
diff --git a/pdftops/GfxFont.h b/pdftops/GfxFont.h
index 6853b1cc1a..e51635632a 100644
--- a/pdftops/GfxFont.h
+++ b/pdftops/GfxFont.h
@@ -98,7 +98,7 @@ class GfxFont {
public:
// Constructor.
- GfxFont(const char *tag1, Ref id1, Dict *fontDict);
+ GfxFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict);
// Destructor.
~GfxFont();
@@ -110,7 +110,7 @@ public:
Ref getID() { return id; }
// Does this font match the tag?
- GBool matches(const char *tag1) { return !tag->cmp(tag1); }
+ GBool matches(char *tagA) { return !tag->cmp(tagA); }
// Get base font name.
GString *getName() { return name; }
@@ -128,8 +128,8 @@ public:
// Get the PostScript font name for the embedded font. Returns
// NULL if there is no embedded font.
- const char *getEmbeddedFontName()
- { return embFontName ? embFontName->getCString() : (const char *)NULL; }
+ char *getEmbeddedFontName()
+ { return embFontName ? embFontName->getCString() : (char *)NULL; }
// Get the name of the external font file. Returns NULL if there
// is no external font file.
@@ -156,10 +156,10 @@ public:
FontEncoding *getEncoding() { return encoding; }
// Return the character name associated with .
- const char *getCharName(int code) { return encoding->getCharName(code); }
+ char *getCharName(int code) { return encoding->getCharName(code); }
// Return the code associated with .
- int getCharCode(const char *charName) { return encoding->getCharCode(charName); }
+ int getCharCode(char *charName) { return encoding->getCharCode(charName); }
// Return the Type 3 CharProc for the character associated with .
Object *getCharProc(int code, Object *proc);
@@ -174,14 +174,21 @@ public:
// Return the font matrix.
double *getFontMatrix() { return fontMat; }
+ // Return the font bounding box.
+ double *getFontBBox() { return fontBBox; }
+
+ // Return the ascent and descent values.
+ double getAscent() { return ascent; }
+ double getDescent() { return descent; }
+
// Read an external or embedded font file into a buffer.
- const char *readExtFontFile(int *len);
- const char *readEmbFontFile(int *len);
+ char *readExtFontFile(int *len);
+ char *readEmbFontFile(XRef *xref, int *len);
private:
- void getEncAndWidths(Dict *fontDict, BuiltinFont *builtinFont,
- int missingWidth);
+ void getEncAndWidths(XRef *xref, Dict *fontDict,
+ BuiltinFont *builtinFont, int missingWidth);
void findExtFontFile();
void makeWidths(Dict *fontDict, FontEncoding *builtinEncoding,
Gushort *builtinWidths, int missingWidth);
@@ -198,6 +205,9 @@ private:
GString *extFontFile; // external font file name
Object charProcs; // Type3 CharProcs dictionary
double fontMat[6]; // font matrix
+ double fontBBox[4]; // font bounding box
+ double ascent; // max height above baseline
+ double descent; // max depth below baseline
union {
FontEncoding *encoding; // 8-bit font encoding
struct {
@@ -219,13 +229,13 @@ class GfxFontDict {
public:
// Build the font dictionary, given the PDF font dictionary.
- GfxFontDict(Dict *fontDict);
+ GfxFontDict(XRef *xref, Dict *fontDict);
// Destructor.
~GfxFontDict();
// Get the specified font.
- GfxFont *lookup(const char *tag);
+ GfxFont *lookup(char *tag);
// Iterative access.
int getNumFonts() { return numFonts; }
diff --git a/pdftops/GfxState.cxx b/pdftops/GfxState.cxx
index 1abf9a56ec..1407415700 100644
--- a/pdftops/GfxState.cxx
+++ b/pdftops/GfxState.cxx
@@ -17,6 +17,7 @@
#include "Error.h"
#include "Object.h"
#include "Array.h"
+#include "Page.h"
#include "GfxState.h"
//------------------------------------------------------------------------
@@ -261,9 +262,9 @@ GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
whiteX = whiteY = whiteZ = 1;
blackX = blackY = blackZ = 0;
gammaR = gammaG = gammaB = 1;
- m[0] = 1; m[1] = 0; m[2] = 0;
- m[3] = 0; m[4] = 1; m[5] = 0;
- m[6] = 0; m[7] = 0; m[8] = 1;
+ mat[0] = 1; mat[1] = 0; mat[2] = 0;
+ mat[3] = 0; mat[4] = 1; mat[5] = 0;
+ mat[6] = 0; mat[7] = 0; mat[8] = 1;
}
GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
@@ -284,7 +285,7 @@ GfxColorSpace *GfxCalRGBColorSpace::copy() {
cs->gammaG = gammaG;
cs->gammaB = gammaB;
for (i = 0; i < 9; ++i) {
- cs->m[i] = m[i];
+ cs->mat[i] = mat[i];
}
return cs;
}
@@ -344,7 +345,7 @@ GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
obj2.arrayGetLength() == 9) {
for (i = 0; i < 9; ++i) {
obj2.arrayGet(i, &obj3);
- cs->m[i] = obj3.getNum();
+ cs->mat[i] = obj3.getNum();
obj3.free();
}
}
@@ -609,11 +610,11 @@ void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
// GfxICCBasedColorSpace
//------------------------------------------------------------------------
-GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt,
- Ref *iccProfileStream) {
- this->nComps = nComps;
- this->alt = alt;
- this->iccProfileStream = *iccProfileStream;
+GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA) {
+ nComps = nCompsA;
+ alt = altA;
+ iccProfileStream = *iccProfileStreamA;
rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
}
@@ -636,19 +637,19 @@ GfxColorSpace *GfxICCBasedColorSpace::copy() {
GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
GfxICCBasedColorSpace *cs;
- Ref iccProfileStream;
- int nComps;
- GfxColorSpace *alt;
+ Ref iccProfileStreamA;
+ int nCompsA;
+ GfxColorSpace *altA;
Dict *dict;
Object obj1, obj2, obj3;
int i;
arr->getNF(1, &obj1);
if (obj1.isRef()) {
- iccProfileStream = obj1.getRef();
+ iccProfileStreamA = obj1.getRef();
} else {
- iccProfileStream.num = 0;
- iccProfileStream.gen = 0;
+ iccProfileStreamA.num = 0;
+ iccProfileStreamA.gen = 0;
}
obj1.free();
arr->get(1, &obj1);
@@ -664,19 +665,19 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
obj1.free();
return NULL;
}
- nComps = obj2.getInt();
+ nCompsA = obj2.getInt();
obj2.free();
if (dict->lookup("Alternate", &obj2)->isNull() ||
- !(alt = GfxColorSpace::parse(&obj2))) {
- switch (nComps) {
+ !(altA = GfxColorSpace::parse(&obj2))) {
+ switch (nCompsA) {
case 1:
- alt = new GfxDeviceGrayColorSpace();
+ altA = new GfxDeviceGrayColorSpace();
break;
case 3:
- alt = new GfxDeviceRGBColorSpace();
+ altA = new GfxDeviceRGBColorSpace();
break;
case 4:
- alt = new GfxDeviceCMYKColorSpace();
+ altA = new GfxDeviceCMYKColorSpace();
break;
default:
error(-1, "Bad ICCBased color space - invalid N");
@@ -686,10 +687,10 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
}
}
obj2.free();
- cs = new GfxICCBasedColorSpace(nComps, alt, &iccProfileStream);
+ cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
if (dict->lookup("Range", &obj2)->isArray() &&
- obj2.arrayGetLength() == 2 * nComps) {
- for (i = 0; i < nComps; ++i) {
+ obj2.arrayGetLength() == 2 * nCompsA) {
+ for (i = 0; i < nCompsA; ++i) {
obj2.arrayGet(2*i, &obj3);
cs->rangeMin[i] = obj3.getNum();
obj3.free();
@@ -730,12 +731,12 @@ void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
// GfxIndexedColorSpace
//------------------------------------------------------------------------
-GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *base,
- int indexHigh) {
- this->base = base;
- this->indexHigh = indexHigh;
- this->lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
- sizeof(Guchar));
+GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
+ int indexHighA) {
+ base = baseA;
+ indexHigh = indexHighA;
+ lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
+ sizeof(Guchar));
}
GfxIndexedColorSpace::~GfxIndexedColorSpace() {
@@ -754,8 +755,8 @@ GfxColorSpace *GfxIndexedColorSpace::copy() {
GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
GfxIndexedColorSpace *cs;
- GfxColorSpace *base;
- int indexHigh;
+ GfxColorSpace *baseA;
+ int indexHighA;
Object obj1;
int x;
char *s;
@@ -766,7 +767,7 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
goto err1;
}
arr->get(1, &obj1);
- if (!(base = GfxColorSpace::parse(&obj1))) {
+ if (!(baseA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Indexed color space (base color space)");
goto err2;
}
@@ -775,14 +776,14 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
error(-1, "Bad Indexed color space (hival)");
goto err2;
}
- indexHigh = obj1.getInt();
+ indexHighA = obj1.getInt();
obj1.free();
- cs = new GfxIndexedColorSpace(base, indexHigh);
+ cs = new GfxIndexedColorSpace(baseA, indexHighA);
arr->get(3, &obj1);
- n = base->getNComps();
+ n = baseA->getNComps();
if (obj1.isStream()) {
obj1.streamReset();
- for (i = 0; i <= indexHigh; ++i) {
+ for (i = 0; i <= indexHighA; ++i) {
for (j = 0; j < n; ++j) {
if ((x = obj1.streamGetChar()) == EOF) {
error(-1, "Bad Indexed color space (lookup table stream too short)");
@@ -793,12 +794,12 @@ GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
}
obj1.streamClose();
} else if (obj1.isString()) {
- if (obj1.getString()->getLength() < (indexHigh + 1) * n) {
+ if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
error(-1, "Bad Indexed color space (lookup table string too short)");
goto err3;
}
s = obj1.getString()->getCString();
- for (i = 0; i <= indexHigh; ++i) {
+ for (i = 0; i <= indexHighA; ++i) {
for (j = 0; j < n; ++j) {
cs->lookup[i*n + j] = (Guchar)*s++;
}
@@ -868,12 +869,12 @@ void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
// GfxSeparationColorSpace
//------------------------------------------------------------------------
-GfxSeparationColorSpace::GfxSeparationColorSpace(GString *name,
- GfxColorSpace *alt,
- Function *func) {
- this->name = name;
- this->alt = alt;
- this->func = func;
+GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
}
GfxSeparationColorSpace::~GfxSeparationColorSpace() {
@@ -889,9 +890,9 @@ GfxColorSpace *GfxSeparationColorSpace::copy() {
//~ handle the 'All' and 'None' colorants
GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
GfxSeparationColorSpace *cs;
- GString *name;
- GfxColorSpace *alt;
- Function *func;
+ GString *nameA;
+ GfxColorSpace *altA;
+ Function *funcA;
Object obj1;
if (arr->getLength() != 4) {
@@ -902,27 +903,31 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
error(-1, "Bad Separation color space (name)");
goto err2;
}
- name = new GString(obj1.getName());
+ nameA = new GString(obj1.getName());
obj1.free();
arr->get(2, &obj1);
- if (!(alt = GfxColorSpace::parse(&obj1))) {
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Separation color space (alternate color space)");
goto err3;
}
obj1.free();
- func = Function::parse(arr->get(3, &obj1));
- obj1.free();
- if (!func->isOk()) {
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
goto err4;
}
- cs = new GfxSeparationColorSpace(name, alt, func);
+ if (!funcA->isOk()) {
+ goto err5;
+ }
+ obj1.free();
+ cs = new GfxSeparationColorSpace(nameA, altA, funcA);
return cs;
+ err5:
+ delete funcA;
err4:
- delete func;
- delete alt;
+ delete altA;
err3:
- delete name;
+ delete nameA;
err2:
obj1.free();
err1:
@@ -954,12 +959,12 @@ void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
// GfxDeviceNColorSpace
//------------------------------------------------------------------------
-GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nComps,
- GfxColorSpace *alt,
- Function *func) {
- this->nComps = nComps;
- this->alt = alt;
- this->func = func;
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
}
GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
@@ -986,10 +991,10 @@ GfxColorSpace *GfxDeviceNColorSpace::copy() {
//~ handle the 'None' colorant
GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
GfxDeviceNColorSpace *cs;
- int nComps;
- GString *names[gfxColorMaxComps];
- GfxColorSpace *alt;
- Function *func;
+ int nCompsA;
+ GString *namesA[gfxColorMaxComps];
+ GfxColorSpace *altA;
+ Function *funcA;
Object obj1, obj2;
int i;
@@ -1001,40 +1006,44 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
error(-1, "Bad DeviceN color space (names)");
goto err2;
}
- nComps = obj1.arrayGetLength();
- for (i = 0; i < nComps; ++i) {
+ nCompsA = obj1.arrayGetLength();
+ for (i = 0; i < nCompsA; ++i) {
if (!obj1.arrayGet(i, &obj2)->isName()) {
error(-1, "Bad DeviceN color space (names)");
obj2.free();
goto err2;
}
- names[i] = new GString(obj2.getName());
+ namesA[i] = new GString(obj2.getName());
obj2.free();
}
obj1.free();
arr->get(2, &obj1);
- if (!(alt = GfxColorSpace::parse(&obj1))) {
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad DeviceN color space (alternate color space)");
goto err3;
}
obj1.free();
- func = Function::parse(arr->get(3, &obj1));
- obj1.free();
- if (!func->isOk()) {
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
goto err4;
}
- cs = new GfxDeviceNColorSpace(nComps, alt, func);
- for (i = 0; i < nComps; ++i) {
- cs->names[i] = names[i];
+ if (!funcA->isOk()) {
+ goto err5;
+ }
+ obj1.free();
+ cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+ for (i = 0; i < nCompsA; ++i) {
+ cs->names[i] = namesA[i];
}
return cs;
+ err5:
+ delete funcA;
err4:
- delete func;
- delete alt;
+ delete altA;
err3:
- for (i = 0; i < nComps; ++i) {
- delete names[i];
+ for (i = 0; i < nCompsA; ++i) {
+ delete namesA[i];
}
err2:
obj1.free();
@@ -1067,8 +1076,8 @@ void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
// GfxPatternColorSpace
//------------------------------------------------------------------------
-GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *under) {
- this->under = under;
+GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
+ under = underA;
}
GfxPatternColorSpace::~GfxPatternColorSpace() {
@@ -1084,24 +1093,24 @@ GfxColorSpace *GfxPatternColorSpace::copy() {
GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
GfxPatternColorSpace *cs;
- GfxColorSpace *under;
+ GfxColorSpace *underA;
Object obj1;
if (arr->getLength() != 1 && arr->getLength() != 2) {
error(-1, "Bad Pattern color space");
return NULL;
}
- under = NULL;
+ underA = NULL;
if (arr->getLength() == 2) {
arr->get(1, &obj1);
- if (!(under = GfxColorSpace::parse(&obj1))) {
+ if (!(underA = GfxColorSpace::parse(&obj1))) {
error(-1, "Bad Pattern color space (underlying color space)");
obj1.free();
return NULL;
}
obj1.free();
}
- cs = new GfxPatternColorSpace(under);
+ cs = new GfxPatternColorSpace(underA);
return cs;
}
@@ -1122,8 +1131,8 @@ void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
// Pattern
//------------------------------------------------------------------------
-GfxPattern::GfxPattern(int type) {
- this->type = type;
+GfxPattern::GfxPattern(int typeA) {
+ type = typeA;
}
GfxPattern::~GfxPattern() {
@@ -1237,480 +1246,254 @@ GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
}
//------------------------------------------------------------------------
-// Function
+// GfxShading
//------------------------------------------------------------------------
-Function::Function() {
-}
-
-Function::~Function() {
+GfxShading::GfxShading() {
}
-Function *Function::parse(Object *funcObj) {
- Function *func;
- Dict *dict;
- int funcType;
- Object obj1;
-
- if (funcObj->isStream()) {
- dict = funcObj->streamGetDict();
- } else if (funcObj->isDict()) {
- dict = funcObj->getDict();
- } else {
- error(-1, "Expected function dictionary or stream");
- return NULL;
- }
-
- if (!dict->lookup("FunctionType", &obj1)->isInt()) {
- error(-1, "Function type is missing or wrong type");
- obj1.free();
- return NULL;
- }
- funcType = obj1.getInt();
- obj1.free();
-
- if (funcType == 0) {
- func = new SampledFunction(funcObj, dict);
- } else if (funcType == 2) {
- func = new ExponentialFunction(funcObj, dict);
- } else {
- error(-1, "Unimplemented function type");
- return NULL;
- }
- if (!func->isOk()) {
- delete func;
- return NULL;
- }
-
- return func;
+GfxShading::~GfxShading() {
+ delete colorSpace;
}
-GBool Function::init(Dict *dict) {
+GfxShading *GfxShading::parse(Object *obj) {
+ GfxShading *shading;
+ int typeA;
+ GfxColorSpace *colorSpaceA;
+ GfxColor backgroundA;
+ GBool hasBackgroundA;
+ double xMinA, yMinA, xMaxA, yMaxA;
+ GBool hasBBoxA;
Object obj1, obj2;
int i;
- //----- Domain
- if (!dict->lookup("Domain", &obj1)->isArray()) {
- error(-1, "Function is missing domain");
- goto err2;
- }
- m = obj1.arrayGetLength() / 2;
- if (m > funcMaxInputs) {
- error(-1, "Functions with more than %d inputs are unsupported",
- funcMaxInputs);
- goto err2;
- }
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function domain array");
+ shading = NULL;
+ if (obj->isDict()) {
+
+ if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
+ error(-1, "Invalid ShadingType in shading dictionary");
+ obj1.free();
goto err1;
}
- domain[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function domain array");
+ typeA = obj1.getInt();
+ obj1.free();
+ if (typeA != 2) {
+ error(-1, "Unimplemented shading type %d", typeA);
goto err1;
}
- domain[i][1] = obj2.getNum();
- obj2.free();
- }
- obj1.free();
- //----- Range
- hasRange = gFalse;
- n = 0;
- if (dict->lookup("Range", &obj1)->isArray()) {
- hasRange = gTrue;
- n = obj1.arrayGetLength() / 2;
- if (n > funcMaxOutputs) {
- error(-1, "Functions with more than %d outputs are unsupported",
- funcMaxOutputs);
- goto err2;
- }
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function range array");
- goto err1;
- }
- range[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function range array");
- goto err1;
- }
- range[i][1] = obj2.getNum();
- obj2.free();
+ obj->dictLookup("ColorSpace", &obj1);
+ if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad color space in shading dictionary");
+ obj1.free();
+ goto err1;
}
obj1.free();
- }
-
- return gTrue;
- err1:
- obj2.free();
- err2:
- obj1.free();
- return gFalse;
-}
-
-//------------------------------------------------------------------------
-// SampledFunction
-//------------------------------------------------------------------------
-
-SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
- Stream *str;
- int nSamples, sampleBits;
- double sampleMul;
- Object obj1, obj2;
- Guint buf, bitMask;
- int bits;
- int s;
- int i;
-
- samples = NULL;
- ok = gFalse;
-
- //----- initialize the generic stuff
- if (!init(dict)) {
- goto err1;
- }
- if (!hasRange) {
- error(-1, "Type 0 function is missing range");
- goto err1;
- }
-
- //----- get the stream
- if (!funcObj->isStream()) {
- error(-1, "Type 0 function isn't a stream");
- goto err1;
- }
- str = funcObj->getStream();
-
- //----- Size
- if (!dict->lookup("Size", &obj1)->isArray() ||
- obj1.arrayGetLength() != m) {
- error(-1, "Function has missing or invalid size array");
- goto err2;
- }
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(i, &obj2);
- if (!obj2.isInt()) {
- error(-1, "Illegal value in function size array");
- goto err3;
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ backgroundA.c[i] = 0;
}
- sampleSize[i] = obj2.getInt();
- obj2.free();
- }
- obj1.free();
-
- //----- BitsPerSample
- if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
- error(-1, "Function has missing or invalid BitsPerSample");
- goto err2;
- }
- sampleBits = obj1.getInt();
- sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
- obj1.free();
-
- //----- Encode
- if (dict->lookup("Encode", &obj1)->isArray() &&
- obj1.arrayGetLength() == 2*m) {
- for (i = 0; i < m; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function encode array");
- goto err3;
- }
- encode[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function encode array");
- goto err3;
+ hasBackgroundA = gFalse;
+ if (obj->dictLookup("Background", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
+ hasBackgroundA = gTrue;
+ for (i = 0; i < colorSpaceA->getNComps(); ++i) {
+ backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
+ obj2.free();
+ }
+ } else {
+ error(-1, "Bad Background in shading dictionary");
}
- encode[i][1] = obj2.getNum();
- obj2.free();
- }
- } else {
- for (i = 0; i < m; ++i) {
- encode[i][0] = 0;
- encode[i][1] = sampleSize[i] - 1;
}
- }
- obj1.free();
+ obj1.free();
- //----- Decode
- if (dict->lookup("Decode", &obj1)->isArray() &&
- obj1.arrayGetLength() == 2*n) {
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(2*i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function decode array");
- goto err3;
+ xMinA = yMinA = xMaxA = yMaxA = 0;
+ hasBBoxA = gFalse;
+ if (obj->dictLookup("BBox", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 4) {
+ hasBBoxA = gTrue;
+ xMinA = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ yMinA = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMaxA = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMaxA = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Bad BBox in shading dictionary");
}
- decode[i][0] = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2*i+1, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function decode array");
- goto err3;
- }
- decode[i][1] = obj2.getNum();
- obj2.free();
- }
- } else {
- for (i = 0; i < n; ++i) {
- decode[i][0] = range[i][0];
- decode[i][1] = range[i][1];
}
- }
- obj1.free();
+ obj1.free();
- //----- samples
- nSamples = n;
- for (i = 0; i < m; ++i)
- nSamples *= sampleSize[i];
- samples = (double *)gmalloc(nSamples * sizeof(double));
- buf = 0;
- bits = 0;
- bitMask = (1 << sampleBits) - 1;
- str->reset();
- for (i = 0; i < nSamples; ++i) {
- if (sampleBits == 8) {
- s = str->getChar();
- } else if (sampleBits == 16) {
- s = str->getChar();
- s = (s << 8) + str->getChar();
- } else if (sampleBits == 32) {
- s = str->getChar();
- s = (s << 8) + str->getChar();
- s = (s << 8) + str->getChar();
- s = (s << 8) + str->getChar();
- } else {
- while (bits < sampleBits) {
- buf = (buf << 8) | (str->getChar() & 0xff);
- bits += 8;
- }
- s = (buf >> (bits - sampleBits)) & bitMask;
- bits -= sampleBits;
+ shading = GfxAxialShading::parse(obj->getDict());
+
+ if (shading) {
+ shading->type = typeA;
+ shading->colorSpace = colorSpaceA;
+ shading->background = backgroundA;
+ shading->hasBackground = hasBackgroundA;
+ shading->xMin = xMinA;
+ shading->yMin = yMinA;
+ shading->xMax = xMaxA;
+ shading->yMax = yMaxA;
+ shading->hasBBox = hasBBoxA;
}
- samples[i] = (double)s * sampleMul;
}
- str->close();
- ok = gTrue;
- return;
+ return shading;
- err3:
- obj2.free();
- err2:
- obj1.free();
err1:
- return;
-}
-
-SampledFunction::~SampledFunction() {
- if (samples) {
- gfree(samples);
- }
+ return NULL;
}
-SampledFunction::SampledFunction(SampledFunction *func) {
- int nSamples, i;
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
- memcpy(this, func, sizeof(SampledFunction));
+GfxAxialShading::GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A) {
+ int i;
- nSamples = n;
- for (i = 0; i < m; ++i) {
- nSamples *= sampleSize[i];
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
}
- samples = (double *)gmalloc(nSamples * sizeof(double));
- memcpy(samples, func->samples, nSamples * sizeof(double));
+ extend0 = extend0A;
+ extend1 = extend1A;
}
-void SampledFunction::transform(double *in, double *out) {
- double e[4];
- double s;
- double x0, x1;
- int e0, e1;
- double efrac;
+GfxAxialShading::~GfxAxialShading() {
int i;
- // map input values into sample array
- for (i = 0; i < m; ++i) {
- e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
- (encode[i][1] - encode[i][0]) + encode[i][0];
- if (e[i] < 0) {
- e[i] = 0;
- } else if (e[i] > sampleSize[i] - 1) {
- e[i] = sampleSize[i] - 1;
- }
- }
-
- for (i = 0; i < n; ++i) {
-
- // m-linear interpolation
- // (only m=1 is currently supported)
- e0 = (int)floor(e[0]);
- e1 = (int)ceil(e[0]);
- efrac = e[0] - e0;
- x0 = samples[e0 * n + i];
- x1 = samples[e1 * n + i];
- s = (1 - efrac) * x0 + efrac * x1;
-
- // map output values to range
- out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
- if (out[i] < range[i][0]) {
- out[i] = range[i][0];
- } else if (out[i] > range[i][1]) {
- out[i] = range[i][1];
- }
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
}
}
-//------------------------------------------------------------------------
-// ExponentialFunction
-//------------------------------------------------------------------------
-
-ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
+GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
+ double x0A, y0A, x1A, y1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
Object obj1, obj2;
- GBool hasN;
int i;
- ok = gFalse;
- hasN = gFalse;
-
- //----- initialize the generic stuff
- if (!init(dict)) {
- goto err1;
- }
- if (m != 1) {
- error(-1, "Exponential function with more than one input");
+ x0A = y0A = x1A = y1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
goto err1;
}
+ obj1.free();
- //----- default values
- for (i = 0; i < funcMaxOutputs; ++i) {
- c0[i] = 0;
- c1[i] = 1;
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
}
+ obj1.free();
- //----- C0
- if (dict->lookup("C0", &obj1)->isArray()) {
- if (!hasN) {
- n = obj1.arrayGetLength();
- } else if (obj1.arrayGetLength() != n) {
- error(-1, "Function's C0 array is wrong length");
- goto err2;
- }
- for (i = 0; i < n; ++i) {
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ for (i = 0; i < nFuncsA; ++i) {
obj1.arrayGet(i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function C0 array");
- goto err3;
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
}
- c0[i] = obj2.getNum();
obj2.free();
}
- obj1.free();
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
}
-
- //----- C1
- if (dict->lookup("C1", &obj1)->isArray()) {
- if (!hasN) {
- n = obj1.arrayGetLength();
- } else if (obj1.arrayGetLength() != n) {
- error(-1, "Function's C1 array is wrong length");
+ obj1.free();
+ for (i = 0; i < nFuncsA; ++i) {
+ if (!funcsA[i]->isOk()) {
goto err2;
}
- for (i = 0; i < n; ++i) {
- obj1.arrayGet(i, &obj2);
- if (!obj2.isNum()) {
- error(-1, "Illegal value in function C1 array");
- goto err3;
- }
- c1[i] = obj2.getNum();
- obj2.free();
- }
- obj1.free();
}
- //----- N (exponent)
- if (!dict->lookup("N", &obj1)->isNum()) {
- error(-1, "Function has missing or invalid N");
- goto err2;
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
}
- e = obj1.getNum();
obj1.free();
- ok = gTrue;
- return;
+ return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
- err3:
- obj2.free();
err2:
- obj1.free();
+ for (i = 0; i < nFuncsA; ++i) {
+ delete funcsA[i];
+ }
err1:
- return;
-}
-
-ExponentialFunction::~ExponentialFunction() {
-}
-
-ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
- memcpy(this, func, sizeof(ExponentialFunction));
+ return NULL;
}
-void ExponentialFunction::transform(double *in, double *out) {
- double x;
+void GfxAxialShading::getColor(double t, GfxColor *color) {
int i;
- if (in[0] < domain[0][0]) {
- x = domain[0][0];
- } else if (in[0] > domain[0][1]) {
- x = domain[0][1];
- } else {
- x = in[0];
- }
- for (i = 0; i < n; ++i) {
- out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
- if (hasRange) {
- if (out[i] < range[i][0]) {
- out[i] = range[i][0];
- } else if (out[i] > range[i][1]) {
- out[i] = range[i][1];
- }
- }
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &color->c[i]);
}
- return;
}
//------------------------------------------------------------------------
// GfxImageColorMap
//------------------------------------------------------------------------
-GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
- GfxColorSpace *colorSpace) {
+GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
+ GfxColorSpace *colorSpaceA) {
GfxIndexedColorSpace *indexedCS;
GfxSeparationColorSpace *sepCS;
int maxPixel, indexHigh;
Guchar *lookup2;
Function *sepFunc;
Object obj;
- double x;
+ double x[gfxColorMaxComps];
double y[gfxColorMaxComps];
int i, j, k;
ok = gTrue;
// bits per component and color space
- this->bits = bits;
+ bits = bitsA;
maxPixel = (1 << bits) - 1;
- this->colorSpace = colorSpace;
+ colorSpace = colorSpaceA;
// get decode map
if (decode->isNull()) {
@@ -1783,8 +1566,8 @@ GfxImageColorMap::GfxImageColorMap(int bits, Object *decode,
lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
sepFunc = sepCS->getFunc();
for (i = 0; i <= maxPixel; ++i) {
- x = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
- sepFunc->transform(&x, y);
+ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+ sepFunc->transform(x, y);
for (k = 0; k < nComps2; ++k) {
lookup[i*nComps2 + k] = y[k];
}
@@ -2014,14 +1797,14 @@ void GfxPath::curveTo(double x1, double y1, double x2, double y2,
// GfxState
//------------------------------------------------------------------------
-GfxState::GfxState(double dpi, double px1a, double py1a,
- double px2a, double py2a, int rotate, GBool upsideDown) {
+GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
+ GBool upsideDown) {
double k;
- px1 = px1a;
- py1 = py1a;
- px2 = px2a;
- py2 = py2a;
+ px1 = pageBox->x1;
+ py1 = pageBox->y1;
+ px2 = pageBox->x2;
+ py2 = pageBox->y2;
k = dpi / 72.0;
if (rotate == 90) {
ctm[0] = 0;
@@ -2095,6 +1878,11 @@ GfxState::GfxState(double dpi, double px1a, double py1a,
curX = curY = 0;
lineX = lineY = 0;
+ clipXMin = 0;
+ clipYMin = 0;
+ clipXMax = pageWidth;
+ clipYMax = pageHeight;
+
saved = NULL;
}
@@ -2233,6 +2021,47 @@ void GfxState::clearPath() {
path = new GfxPath();
}
+void GfxState::clip() {
+ double xMin, yMin, xMax, yMax, x, y;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
+}
+
void GfxState::textShift(double tx) {
double dx, dy;
diff --git a/pdftops/GfxState.h b/pdftops/GfxState.h
index 2056c4d1fb..a628f6bf1f 100644
--- a/pdftops/GfxState.h
+++ b/pdftops/GfxState.h
@@ -15,16 +15,17 @@
#include "gtypes.h"
#include "Object.h"
+#include "Function.h"
class Array;
-class Function;
class GfxFont;
+struct PDFRectangle;
//------------------------------------------------------------------------
// GfxColor
//------------------------------------------------------------------------
-#define gfxColorMaxComps 8
+#define gfxColorMaxComps funcMaxOutputs
struct GfxColor {
double c[gfxColorMaxComps];
@@ -201,14 +202,14 @@ public:
double getGammaR() { return gammaR; }
double getGammaG() { return gammaG; }
double getGammaB() { return gammaB; }
- double *getMatrix() { return m; }
+ double *getMatrix() { return mat; }
private:
double whiteX, whiteY, whiteZ; // white point
double blackX, blackY, blackZ; // black point
double gammaR, gammaG, gammaB; // gamma values
- double m[9]; // ABC -> XYZ transform matrix
+ double mat[9]; // ABC -> XYZ transform matrix
};
//------------------------------------------------------------------------
@@ -283,8 +284,8 @@ private:
class GfxICCBasedColorSpace: public GfxColorSpace {
public:
- GfxICCBasedColorSpace(int nComps, GfxColorSpace *alt,
- Ref *iccProfileStream);
+ GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA);
virtual ~GfxICCBasedColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csICCBased; }
@@ -320,7 +321,7 @@ private:
class GfxIndexedColorSpace: public GfxColorSpace {
public:
- GfxIndexedColorSpace(GfxColorSpace *base, int indexHigh);
+ GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA);
virtual ~GfxIndexedColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csIndexed; }
@@ -356,8 +357,8 @@ private:
class GfxSeparationColorSpace: public GfxColorSpace {
public:
- GfxSeparationColorSpace(GString *name, GfxColorSpace *alt,
- Function *func);
+ GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA,
+ Function *funcA);
virtual ~GfxSeparationColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csSeparation; }
@@ -424,7 +425,7 @@ private:
class GfxPatternColorSpace: public GfxColorSpace {
public:
- GfxPatternColorSpace(GfxColorSpace *under);
+ GfxPatternColorSpace(GfxColorSpace *underA);
virtual ~GfxPatternColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csPattern; }
@@ -454,7 +455,7 @@ private:
class GfxPattern {
public:
- GfxPattern(int type);
+ GfxPattern(int typeA);
virtual ~GfxPattern();
static GfxPattern *parse(Object *obj);
@@ -504,94 +505,66 @@ private:
};
//------------------------------------------------------------------------
-// Function
+// GfxShading
//------------------------------------------------------------------------
-#define funcMaxInputs 1
-#define funcMaxOutputs 8
-
-class Function {
+class GfxShading {
public:
- Function();
-
- virtual ~Function();
-
- // Construct a function. Returns NULL if unsuccessful.
- static Function *parse(Object *funcObj);
-
- // Initialize the entries common to all function types.
- GBool init(Dict *dict);
-
- virtual Function *copy() = 0;
-
- // Return size of input and output tuples.
- int getInputSize() { return m; }
- int getOutputSize() { return n; }
+ GfxShading();
+ virtual ~GfxShading();
- // Transform an input tuple into an output tuple.
- virtual void transform(double *in, double *out) = 0;
+ static GfxShading *parse(Object *obj);
- virtual GBool isOk() = 0;
+ int getType() { return type; }
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+ GfxColor *getBackground() { return &background; }
+ GBool getHasBackground() { return hasBackground; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ GBool getHasBBox() { return hasBBox; }
-protected:
+private:
- int m, n; // size of input and output tuples
- double // min and max values for function domain
- domain[funcMaxInputs][2];
- double // min and max values for function range
- range[funcMaxOutputs][2];
- GBool hasRange; // set if range is defined
+ int type;
+ GfxColorSpace *colorSpace;
+ GfxColor background;
+ GBool hasBackground;
+ double xMin, yMin, xMax, yMax;
+ GBool hasBBox;
};
//------------------------------------------------------------------------
-// SampledFunction
+// GfxAxialShading
//------------------------------------------------------------------------
-class SampledFunction: public Function {
+class GfxAxialShading: public GfxShading {
public:
- SampledFunction(Object *funcObj, Dict *dict);
- virtual ~SampledFunction();
- virtual Function *copy() { return new SampledFunction(this); }
- virtual void transform(double *in, double *out);
- virtual GBool isOk() { return ok; }
-
-private:
-
- SampledFunction(SampledFunction *func);
-
- int // number of samples for each domain element
- sampleSize[funcMaxInputs];
- double // min and max values for domain encoder
- encode[funcMaxInputs][2];
- double // min and max values for range decoder
- decode[funcMaxOutputs][2];
- double *samples; // the samples
- GBool ok;
-};
-
-//------------------------------------------------------------------------
-// ExponentialFunction
-//------------------------------------------------------------------------
+ GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ virtual ~GfxAxialShading();
-class ExponentialFunction: public Function {
-public:
+ static GfxAxialShading *parse(Dict *dict);
- ExponentialFunction(Object *funcObj, Dict *dict);
- virtual ~ExponentialFunction();
- virtual Function *copy() { return new ExponentialFunction(this); }
- virtual void transform(double *in, double *out);
- virtual GBool isOk() { return ok; }
+ void getCoords(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+ double getDomain0() { return t0; }
+ double getDomain1() { return t1; }
+ void getColor(double t, GfxColor *color);
+ GBool getExtend0() { return extend0; }
+ GBool getExtend1() { return extend1; }
private:
- ExponentialFunction(ExponentialFunction *func);
-
- double c0[funcMaxOutputs];
- double c1[funcMaxOutputs];
- double e;
- GBool ok;
+ double x0, y0, x1, y1;
+ double t0, t1;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+ GBool extend0, extend1;
};
//------------------------------------------------------------------------
@@ -602,7 +575,7 @@ class GfxImageColorMap {
public:
// Constructor.
- GfxImageColorMap(int bits, Object *decode, GfxColorSpace *colorSpace);
+ GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA);
// Destructor.
~GfxImageColorMap();
@@ -750,10 +723,10 @@ class GfxState {
public:
// Construct a default GfxState, for a device with resolution ,
- // page box (,)-(,), page rotation , and
- // coordinate system specified by .
- GfxState(double dpi, double px1a, double py1a,
- double px2a, double py2a, int rotate, GBool upsideDown);
+ // page box , page rotation , and coordinate system
+ // specified by .
+ GfxState(double dpi, PDFRectangle *pageBox, int rotate,
+ GBool upsideDown);
// Destructor.
~GfxState();
@@ -771,6 +744,10 @@ public:
double getPageHeight() { return pageHeight; }
GfxColor *getFillColor() { return &fillColor; }
GfxColor *getStrokeColor() { return &strokeColor; }
+ void getFillGray(double *gray)
+ { fillColorSpace->getGray(&fillColor, gray); }
+ void getStrokeGray(double *gray)
+ { strokeColorSpace->getGray(&fillColor, gray); }
void getFillRGB(GfxRGB *rgb)
{ fillColorSpace->getRGB(&fillColor, rgb); }
void getStrokeRGB(GfxRGB *rgb)
@@ -804,6 +781,8 @@ public:
GfxPath *getPath() { return path; }
double getCurX() { return curX; }
double getCurY() { return curY; }
+ void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax)
+ { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; }
double getLineX() { return lineX; }
double getLineY() { return lineY; }
@@ -848,9 +827,9 @@ public:
void setFlatness(int flatness1) { flatness = flatness1; }
void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; }
void setLineCap(int lineCap1) { lineCap = lineCap1; }
- void setMiterLimit(double miterLimit1) { miterLimit = miterLimit1; }
- void setFont(GfxFont *font1, double fontSize1)
- { font = font1; fontSize = fontSize1; }
+ void setMiterLimit(double limit) { miterLimit = limit; }
+ void setFont(GfxFont *fontA, double fontSizeA)
+ { font = fontA; fontSize = fontSizeA; }
void setTextMat(double a, double b, double c,
double d, double e, double f)
{ textMat[0] = a; textMat[1] = b; textMat[2] = c;
@@ -861,12 +840,12 @@ public:
{ wordSpace = space; }
void setHorizScaling(double scale)
{ horizScaling = 0.01 * scale; }
- void setLeading(double leading1)
- { leading = leading1; }
- void setRise(double rise1)
- { rise = rise1; }
- void setRender(int render1)
- { render = render1; }
+ void setLeading(double leadingA)
+ { leading = leadingA; }
+ void setRise(double riseA)
+ { rise = riseA; }
+ void setRender(int renderA)
+ { render = renderA; }
// Add to path.
void moveTo(double x, double y)
@@ -880,6 +859,9 @@ public:
{ path->close(); curX = path->getLastX(); curY = path->getLastY(); }
void clearPath();
+ // Update clip region.
+ void clip();
+
// Text position.
void textMoveTo(double tx, double ty)
{ lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); }
@@ -929,6 +911,9 @@ private:
double curX, curY; // current point (user coords)
double lineX, lineY; // start of current text line (text coords)
+ double clipXMin, clipYMin, // bounding box for clip region
+ clipXMax, clipYMax;
+
GfxState *saved; // next GfxState on stack
GfxState(GfxState *state);
diff --git a/pdftops/Lexer.cxx b/pdftops/Lexer.cxx
index 4ca8cfe9f5..442566b721 100644
--- a/pdftops/Lexer.cxx
+++ b/pdftops/Lexer.cxx
@@ -44,22 +44,22 @@ static char specialChars[256] = {
// Lexer
//------------------------------------------------------------------------
-Lexer::Lexer(Stream *str) {
+Lexer::Lexer(XRef *xref, Stream *str) {
Object obj;
curStr.initStream(str);
- streams = new Array();
+ streams = new Array(xref);
streams->add(curStr.copy(&obj));
strPtr = 0;
freeArray = gTrue;
curStr.streamReset();
}
-Lexer::Lexer(Object *obj) {
+Lexer::Lexer(XRef *xref, Object *obj) {
Object obj2;
if (obj->isStream()) {
- streams = new Array();
+ streams = new Array(xref);
freeArray = gTrue;
streams->add(obj->copy(&obj2));
} else {
@@ -204,11 +204,15 @@ Object *Lexer::getObj(Object *obj) {
case '(':
++numParen;
+ c2 = c;
break;
case ')':
- if (--numParen == 0)
+ if (--numParen == 0) {
done = gTrue;
+ } else {
+ c2 = c;
+ }
break;
case '\\':
diff --git a/pdftops/Lexer.h b/pdftops/Lexer.h
index 70144b86bc..5edbeda6b1 100644
--- a/pdftops/Lexer.h
+++ b/pdftops/Lexer.h
@@ -16,6 +16,8 @@
#include "Object.h"
#include "Stream.h"
+class XRef;
+
#define tokBufSize 128 // size of token buffer
//------------------------------------------------------------------------
@@ -27,11 +29,11 @@ public:
// Construct a lexer for a single stream. Deletes the stream when
// lexer is deleted.
- Lexer(Stream *str);
+ Lexer(XRef *xref, Stream *str);
// Construct a lexer for a stream or array of streams (assumes obj
// is either a stream or array of streams).
- Lexer(Object *obj);
+ Lexer(XRef *xref, Object *obj);
// Destructor.
~Lexer();
diff --git a/pdftops/Link.cxx b/pdftops/Link.cxx
index a53e0990b8..999c1f202f 100644
--- a/pdftops/Link.cxx
+++ b/pdftops/Link.cxx
@@ -28,11 +28,11 @@ static GString *getFileSpecName(Object *fileSpecObj);
// LinkDest
//------------------------------------------------------------------------
-LinkDest::LinkDest(Array *a, GBool pageIsRef1) {
+LinkDest::LinkDest(Array *a, GBool pageIsRefA) {
Object obj1, obj2;
// initialize fields
- pageIsRef = pageIsRef1;
+ pageIsRef = pageIsRefA;
left = bottom = right = top = zoom = 0;
ok = gFalse;
@@ -384,8 +384,8 @@ LinkNamed::~LinkNamed() {
// LinkUnknown
//------------------------------------------------------------------------
-LinkUnknown::LinkUnknown(const char *action1) {
- action = new GString(action1);
+LinkUnknown::LinkUnknown(char *actionA) {
+ action = new GString(actionA);
}
LinkUnknown::~LinkUnknown() {
@@ -447,11 +447,14 @@ Link::Link(Dict *dict, GString *baseURI) {
// get border
borderW = 0;
if (!dict->lookup("Border", &obj1)->isNull()) {
- if (obj1.isArray() && obj1.arrayGet(2, &obj2)->isNum())
- borderW = obj2.getNum();
- else
- error(-1, "Bad annotation border");
- obj2.free();
+ if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderW = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation border");
+ }
+ obj2.free();
+ }
}
obj1.free();
diff --git a/pdftops/Link.h b/pdftops/Link.h
index a502763525..4d16724788 100644
--- a/pdftops/Link.h
+++ b/pdftops/Link.h
@@ -249,7 +249,7 @@ class LinkUnknown: public LinkAction {
public:
// Build a LinkUnknown with the specified action type.
- LinkUnknown(const char *action1);
+ LinkUnknown(char *actionA);
// Destructor.
virtual ~LinkUnknown();
diff --git a/pdftops/Makefile b/pdftops/Makefile
index 95c601ae41..abc87af72d 100644
--- a/pdftops/Makefile
+++ b/pdftops/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.6 2001/03/02 22:34:16 andy Exp $"
+# "$Id: Makefile,v 1.6.2.1 2001/12/26 16:52:45 mike Exp $"
#
# pdftops filter Makefile for the Common UNIX Printing System (CUPS).
#
@@ -16,7 +16,7 @@ include ../Makedefs
LIBOBJS = Decrypt.o GString.o gfile.o gmempp.o gmem.o parseargs.o \
Array.o Catalog.o Dict.o Error.o FontEncoding.o \
- FontFile.o FormWidget.o Gfx.o GfxFont.o GfxState.o \
+ FontFile.o FormWidget.o Function.o Gfx.o GfxFont.o GfxState.o \
Lexer.o Link.o Object.o OutputDev.o Page.o Params.o \
Parser.o PDFDoc.o PSOutputDev.o Stream.o XRef.o
OBJS = pdftops.o $(LIBOBJS)
@@ -43,10 +43,7 @@ clean:
#
install:
- $(MKDIR) $(SERVERBIN)/filter
- $(CHMOD) ugo+rx $(SERVERBIN)
- $(CHMOD) ugo+rx $(SERVERBIN)/filter
- $(RM) $(SERVERBIN)/filter/pdftops
+ $(INSTALL_DIR) $(SERVERBIN)/filter
$(INSTALL_BIN) pdftops $(SERVERBIN)/filter
@@ -89,6 +86,7 @@ FontEncoding.o: gmem.h FontEncoding.h gtypes.h
FontFile.o: gmem.h Error.h config.h FontFile.h gtypes.h GString.h \
FontEncoding.h StdFontInfo.h CompactFontInfo.h
FormWidget.o: FormWidget.h gmem.h Object.h Gfx.h
+Function.o: gmem.h Object.h Dict.h Stream.h Error.h Function.h
Gfx.o: gmem.h Object.h gtypes.h GString.h Array.h Dict.h Stream.h \
Lexer.h Parser.h GfxFont.h FontEncoding.h GfxState.h \
OutputDev.h Params.h Error.h config.h Gfx.h
@@ -130,5 +128,5 @@ XRef.o: gmem.h Object.h gtypes.h GString.h Array.h Dict.h Stream.h \
$(OBJS): ../config.h ../Makedefs
#
-# End of "$Id: Makefile,v 1.6 2001/03/02 22:34:16 andy Exp $".
+# End of "$Id: Makefile,v 1.6.2.1 2001/12/26 16:52:45 mike Exp $".
#
diff --git a/pdftops/Object.cxx b/pdftops/Object.cxx
index b3ebe40f0e..ca671ea2cf 100644
--- a/pdftops/Object.cxx
+++ b/pdftops/Object.cxx
@@ -22,7 +22,7 @@
// Object
//------------------------------------------------------------------------
-const char *objTypeNames[numObjTypes] = {
+char *objTypeNames[numObjTypes] = {
"boolean",
"integer",
"real",
@@ -44,21 +44,21 @@ int Object::numAlloc[numObjTypes] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#endif
-Object *Object::initArray() {
+Object *Object::initArray(XRef *xref) {
initObj(objArray);
- array = new Array();
+ array = new Array(xref);
return this;
}
-Object *Object::initDict() {
+Object *Object::initDict(XRef *xref) {
initObj(objDict);
- dict = new Dict();
+ dict = new Dict(xref);
return this;
}
-Object *Object::initStream(Stream *stream1) {
+Object *Object::initStream(Stream *streamA) {
initObj(objStream);
- stream = stream1;
+ stream = streamA;
return this;
}
@@ -92,7 +92,7 @@ Object *Object::copy(Object *obj) {
return obj;
}
-Object *Object::fetch(Object *obj) {
+Object *Object::fetch(XRef *xref, Object *obj) {
return (type == objRef && xref) ?
xref->fetch(ref.num, ref.gen, obj) : copy(obj);
}
@@ -103,7 +103,7 @@ void Object::free() {
delete string;
break;
case objName:
- gfree((void *)name);
+ gfree(name);
break;
case objArray:
if (!array->decRef()) {
@@ -121,7 +121,7 @@ void Object::free() {
}
break;
case objCmd:
- gfree((void *)cmd);
+ gfree(cmd);
break;
default:
break;
@@ -132,7 +132,7 @@ void Object::free() {
type = objNone;
}
-const char *Object::getTypeName() {
+char *Object::getTypeName() {
return objTypeNames[type];
}
@@ -216,7 +216,5 @@ void Object::memCheck(FILE *f) {
fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]);
}
}
-#else
- (void)f;
#endif
}
diff --git a/pdftops/Object.h b/pdftops/Object.h
index d5132efa5a..49af586139 100644
--- a/pdftops/Object.h
+++ b/pdftops/Object.h
@@ -19,6 +19,7 @@
#include "gmem.h"
#include "GString.h"
+class XRef;
class Array;
class Dict;
class Stream;
@@ -78,27 +79,25 @@ public:
type(objNone) {}
// Initialize an object.
- Object *initBool(GBool booln1)
- { initObj(objBool); booln = booln1; return this; }
- Object *initInt(int intg1)
- { initObj(objInt); intg = intg1; return this; }
- Object *initReal(double real1)
- { initObj(objReal); real = real1; return this; }
- Object *initString(GString *string1)
- { initObj(objString); string = string1; return this; }
- Object *initName(const char *name1)
- { initObj(objName); name = copyString(name1); return this; }
+ Object *initBool(GBool boolnA)
+ { initObj(objBool); booln = boolnA; return this; }
+ Object *initInt(int intgA)
+ { initObj(objInt); intg = intgA; return this; }
+ Object *initReal(double realA)
+ { initObj(objReal); real = realA; return this; }
+ Object *initString(GString *stringA)
+ { initObj(objString); string = stringA; return this; }
+ Object *initName(char *nameA)
+ { initObj(objName); name = copyString(nameA); return this; }
Object *initNull()
{ initObj(objNull); return this; }
- Object *initArray();
- Object *initDict();
- Object *initDict(Dict *dict1)
- { initObj(objDict); dict = dict1; return this; }
- Object *initStream(Stream *stream1);
- Object *initRef(int num1, int gen1)
- { initObj(objRef); ref.num = num1; ref.gen = gen1; return this; }
- Object *initCmd(const char *cmd1)
- { initObj(objCmd); cmd = copyString(cmd1); return this; }
+ Object *initArray(XRef *xref);
+ Object *initDict(XRef *xref);
+ Object *initStream(Stream *streamA);
+ Object *initRef(int numA, int genA)
+ { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
+ Object *initCmd(char *cmdA)
+ { initObj(objCmd); cmd = copyString(cmdA); return this; }
Object *initError()
{ initObj(objError); return this; }
Object *initEOF()
@@ -109,7 +108,7 @@ public:
// If object is a Ref, fetch and return the referenced object.
// Otherwise, return a copy of the object.
- Object *fetch(Object *obj);
+ Object *fetch(XRef *xref, Object *obj);
// Free object contents.
void free();
@@ -133,12 +132,12 @@ public:
GBool isNone() { return type == objNone; }
// Special type checking.
- GBool isName(const char *name1)
- { return type == objName && !strcmp(name, name1); }
- GBool isDict(const char *dictType);
- GBool isStream(const char *dictType);
- GBool isCmd(const char *cmd1)
- { return type == objCmd && !strcmp(cmd, cmd1); }
+ GBool isName(char *nameA)
+ { return type == objName && !strcmp(name, nameA); }
+ GBool isDict(char *dictType);
+ GBool isStream(char *dictType);
+ GBool isCmd(char *cmdA)
+ { return type == objCmd && !strcmp(cmd, cmdA); }
// Accessors. NB: these assume object is of correct type.
GBool getBool() { return booln; }
@@ -146,7 +145,7 @@ public:
double getReal() { return real; }
double getNum() { return type == objInt ? (double)intg : real; }
GString *getString() { return string; }
- const char *getName() { return name; }
+ char *getName() { return name; }
Array *getArray() { return array; }
Dict *getDict() { return dict; }
Stream *getStream() { return stream; }
@@ -162,16 +161,16 @@ public:
// Dict accessors.
int dictGetLength();
- void dictAdd(const char *key, Object *val);
- GBool dictIs(const char *dictType);
- Object *dictLookup(const char *key, Object *obj);
- Object *dictLookupNF(const char *key, Object *obj);
- const char *dictGetKey(int i);
+ void dictAdd(char *key, Object *val);
+ GBool dictIs(char *dictType);
+ Object *dictLookup(char *key, Object *obj);
+ Object *dictLookupNF(char *key, Object *obj);
+ char *dictGetKey(int i);
Object *dictGetVal(int i, Object *obj);
Object *dictGetValNF(int i, Object *obj);
// Stream accessors.
- GBool streamIs(const char *dictType);
+ GBool streamIs(char *dictType);
void streamReset();
void streamClose();
int streamGetChar();
@@ -182,7 +181,7 @@ public:
Dict *streamGetDict();
// Output.
- const char *getTypeName();
+ char *getTypeName();
void print(FILE *f = stdout);
// Memory testing.
@@ -196,12 +195,12 @@ private:
int intg; // integer
double real; // real
GString *string; // string
- const char *name; // name
+ char *name; // name
Array *array; // array
Dict *dict; // dictionary
Stream *stream; // stream
Ref ref; // indirect reference
- const char *cmd; // command
+ char *cmd; // command
};
#ifdef DEBUG_MEM
@@ -237,22 +236,22 @@ inline Object *Object::arrayGetNF(int i, Object *obj)
inline int Object::dictGetLength()
{ return dict->getLength(); }
-inline void Object::dictAdd(const char *key, Object *val)
+inline void Object::dictAdd(char *key, Object *val)
{ dict->add(key, val); }
-inline GBool Object::dictIs(const char *dictType)
+inline GBool Object::dictIs(char *dictType)
{ return dict->is(dictType); }
-inline GBool Object::isDict(const char *dictType)
+inline GBool Object::isDict(char *dictType)
{ return type == objDict && dictIs(dictType); }
-inline Object *Object::dictLookup(const char *key, Object *obj)
+inline Object *Object::dictLookup(char *key, Object *obj)
{ return dict->lookup(key, obj); }
-inline Object *Object::dictLookupNF(const char *key, Object *obj)
+inline Object *Object::dictLookupNF(char *key, Object *obj)
{ return dict->lookupNF(key, obj); }
-inline const char *Object::dictGetKey(int i)
+inline char *Object::dictGetKey(int i)
{ return dict->getKey(i); }
inline Object *Object::dictGetVal(int i, Object *obj)
@@ -267,10 +266,10 @@ inline Object *Object::dictGetValNF(int i, Object *obj)
#include "Stream.h"
-inline GBool Object::streamIs(const char *dictType)
+inline GBool Object::streamIs(char *dictType)
{ return stream->getDict()->is(dictType); }
-inline GBool Object::isStream(const char *dictType)
+inline GBool Object::isStream(char *dictType)
{ return type == objStream && streamIs(dictType); }
inline void Object::streamReset()
diff --git a/pdftops/OutputDev.cxx b/pdftops/OutputDev.cxx
index b90636116b..014b2aef65 100644
--- a/pdftops/OutputDev.cxx
+++ b/pdftops/OutputDev.cxx
@@ -20,29 +20,30 @@
// OutputDev
//------------------------------------------------------------------------
-void OutputDev::setDefaultCTM(double *ctm1) {
+void OutputDev::setDefaultCTM(double *ctm) {
int i;
double det;
- for (i = 0; i < 6; ++i)
- ctm[i] = ctm1[i];
- det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
- ictm[0] = ctm[3] * det;
- ictm[1] = -ctm[1] * det;
- ictm[2] = -ctm[2] * det;
- ictm[3] = ctm[0] * det;
- ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
- ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ for (i = 0; i < 6; ++i) {
+ defCTM[i] = ctm[i];
+ }
+ det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]);
+ defICTM[0] = defCTM[3] * det;
+ defICTM[1] = -defCTM[1] * det;
+ defICTM[2] = -defCTM[2] * det;
+ defICTM[3] = defCTM[0] * det;
+ defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det;
+ defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det;
}
void OutputDev::cvtDevToUser(int dx, int dy, double *ux, double *uy) {
- *ux = ictm[0] * dx + ictm[2] * dy + ictm[4];
- *uy = ictm[1] * dx + ictm[3] * dy + ictm[5];
+ *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4];
+ *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5];
}
void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) {
- *dx = (int)(ctm[0] * ux + ctm[2] * uy + ctm[4] + 0.5);
- *dy = (int)(ctm[1] * ux + ctm[3] * uy + ctm[5] + 0.5);
+ *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5);
+ *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5);
}
void OutputDev::updateAll(GfxState *state) {
@@ -62,9 +63,6 @@ void OutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
GBool inlineImg) {
int i, j;
- (void)state;
- (void)invert;
-
if (inlineImg) {
str->reset();
j = height * ((width + 7) / 8);
@@ -75,11 +73,9 @@ void OutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
- GBool inlineImg) {
+ int *maskColors, GBool inlineImg) {
int i, j;
- (void)state;
-
if (inlineImg) {
str->reset();
j = height * ((width * colorMap->getNumPixelComps() *
diff --git a/pdftops/OutputDev.h b/pdftops/OutputDev.h
index 7128183fae..c332fa933f 100644
--- a/pdftops/OutputDev.h
+++ b/pdftops/OutputDev.h
@@ -48,10 +48,10 @@ public:
//----- initialization and control
// Set default transform matrix.
- virtual void setDefaultCTM(double *ctm1);
+ virtual void setDefaultCTM(double *ctm);
// Start a page.
- virtual void startPage(int, GfxState *) {}
+ virtual void startPage(int pageNum, GfxState *state) {}
// End a page.
virtual void endPage() {}
@@ -66,56 +66,56 @@ public:
virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy);
//----- link borders
- virtual void drawLink(Link *, Catalog *) {}
+ virtual void drawLink(Link *link, Catalog *catalog) {}
//----- save/restore graphics state
- virtual void saveState(GfxState *) {}
- virtual void restoreState(GfxState *) {}
+ virtual void saveState(GfxState *state) {}
+ virtual void restoreState(GfxState *state) {}
//----- update graphics state
virtual void updateAll(GfxState *state);
- virtual void updateCTM(GfxState *, double, double,
- double, double, double, double) {}
- virtual void updateLineDash(GfxState *) {}
- virtual void updateFlatness(GfxState *) {}
- virtual void updateLineJoin(GfxState *) {}
- virtual void updateLineCap(GfxState *) {}
- virtual void updateMiterLimit(GfxState *) {}
- virtual void updateLineWidth(GfxState *) {}
- virtual void updateFillColor(GfxState *) {}
- virtual void updateStrokeColor(GfxState *) {}
- virtual void updateFillOpacity(GfxState *) {}
- virtual void updateStrokeOpacity(GfxState *) {}
-
- //----- update text
- virtual void updateFont(GfxState *) {}
- virtual void updateTextMat(GfxState *) {}
- virtual void updateCharSpace(GfxState *) {}
- virtual void updateRender(GfxState *) {}
- virtual void updateRise(GfxState *) {}
- virtual void updateWordSpace(GfxState *) {}
- virtual void updateHorizScaling(GfxState *) {}
- virtual void updateTextPos(GfxState *) {}
- virtual void updateTextShift(GfxState *, double) {}
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32) {}
+ virtual void updateLineDash(GfxState *state) {}
+ virtual void updateFlatness(GfxState *state) {}
+ virtual void updateLineJoin(GfxState *state) {}
+ virtual void updateLineCap(GfxState *state) {}
+ virtual void updateMiterLimit(GfxState *state) {}
+ virtual void updateLineWidth(GfxState *state) {}
+ virtual void updateFillColor(GfxState *state) {}
+ virtual void updateStrokeColor(GfxState *state) {}
+ virtual void updateFillOpacity(GfxState *state) {}
+ virtual void updateStrokeOpacity(GfxState *state) {}
+
+ //----- update text state
+ virtual void updateFont(GfxState *state) {}
+ virtual void updateTextMat(GfxState *state) {}
+ virtual void updateCharSpace(GfxState *state) {}
+ virtual void updateRender(GfxState *state) {}
+ virtual void updateRise(GfxState *state) {}
+ virtual void updateWordSpace(GfxState *state) {}
+ virtual void updateHorizScaling(GfxState *state) {}
+ virtual void updateTextPos(GfxState *state) {}
+ virtual void updateTextShift(GfxState *state, double shift) {}
//----- path painting
- virtual void stroke(GfxState *) {}
- virtual void fill(GfxState *) {}
- virtual void eoFill(GfxState *) {}
+ virtual void stroke(GfxState *state) {}
+ virtual void fill(GfxState *state) {}
+ virtual void eoFill(GfxState *state) {}
//----- path clipping
- virtual void clip(GfxState *) {}
- virtual void eoClip(GfxState *) {}
+ virtual void clip(GfxState *state) {}
+ virtual void eoClip(GfxState *state) {}
//----- text drawing
- virtual void beginString(GfxState *, GString *) {}
- virtual void endString(GfxState *) {}
- virtual void drawChar(GfxState *, double, double,
- double, double, Guchar) {}
- virtual void drawChar16(GfxState *, double, double,
- double, double, int) {}
- virtual void drawString(GfxState *, GString *) {}
- virtual void drawString16(GfxState *, GString *) {}
+ virtual void beginString(GfxState *state, GString *s) {}
+ virtual void endString(GfxState *state) {}
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy, Guchar c) {}
+ virtual void drawChar16(GfxState *state, double x, double y,
+ double dx, double dy, int c) {}
+ virtual void drawString(GfxState *state, GString *s) {}
+ virtual void drawString16(GfxState *state, GString *s) {}
//----- image drawing
virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
@@ -123,7 +123,7 @@ public:
GBool inlineImg);
virtual void drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
- GBool inlineImg);
+ int *maskColors, GBool inlineImg);
#if OPI_SUPPORT
//----- OPI functions
@@ -133,8 +133,8 @@ public:
private:
- double ctm[6]; // coordinate transform matrix
- double ictm[6]; // inverse CTM
+ double defCTM[6]; // default coordinate transform matrix
+ double defICTM[6]; // inverse of default CTM
};
#endif
diff --git a/pdftops/PDFDoc.cxx b/pdftops/PDFDoc.cxx
index b10410e540..ae04280543 100644
--- a/pdftops/PDFDoc.cxx
+++ b/pdftops/PDFDoc.cxx
@@ -37,7 +37,8 @@
// PDFDoc
//------------------------------------------------------------------------
-PDFDoc::PDFDoc(GString *fileName1, GString *userPassword) {
+PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
+ GString *userPassword, GBool printCommandsA) {
Object obj;
GString *fileName2;
@@ -48,9 +49,10 @@ PDFDoc::PDFDoc(GString *fileName1, GString *userPassword) {
xref = NULL;
catalog = NULL;
links = NULL;
+ printCommands = printCommandsA;
// try to open file
- fileName = fileName1;
+ fileName = fileNameA;
fileName2 = NULL;
#ifdef VMS
if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) {
@@ -77,36 +79,35 @@ PDFDoc::PDFDoc(GString *fileName1, GString *userPassword) {
obj.initNull();
str = new FileStream(file, 0, -1, &obj);
- ok = setup(userPassword);
+ ok = setup(ownerPassword, userPassword);
}
-PDFDoc::PDFDoc(BaseStream *nstr, GString *userPassword) {
+PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
+ GString *userPassword, GBool printCommandsA) {
ok = gFalse;
fileName = NULL;
file = NULL;
- str = nstr;
+ str = strA;
xref = NULL;
catalog = NULL;
links = NULL;
- ok = setup(userPassword);
+ printCommands = printCommandsA;
+ ok = setup(ownerPassword, userPassword);
}
-GBool PDFDoc::setup(GString *userPassword) {
- Object catObj;
-
+GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
// check header
checkHeader();
// read xref table
- xref = new XRef(str, userPassword);
+ xref = new XRef(str, ownerPassword, userPassword);
if (!xref->isOk()) {
error(-1, "Couldn't read xref table");
return gFalse;
}
// read catalog
- catalog = new Catalog(xref->getCatalog(&catObj));
- catObj.free();
+ catalog = new Catalog(xref, printCommands);
if (!catalog->isOk()) {
error(-1, "Couldn't read page catalog");
return gFalse;
@@ -203,8 +204,8 @@ GBool PDFDoc::isLinearized() {
lin = gFalse;
obj1.initNull();
- parser = new Parser(new Lexer(str->makeSubStream(str->getStart(),
- -1, &obj1)));
+ parser = new Parser(xref, new Lexer(xref, str->makeSubStream(str->getStart(),
+ -1, &obj1)));
parser->getObj(&obj1);
parser->getObj(&obj2);
parser->getObj(&obj3);
@@ -248,4 +249,3 @@ void PDFDoc::getLinks(Page *page) {
links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
obj.free();
}
-
diff --git a/pdftops/PDFDoc.h b/pdftops/PDFDoc.h
index e679db9795..c693e991a1 100644
--- a/pdftops/PDFDoc.h
+++ b/pdftops/PDFDoc.h
@@ -14,13 +14,13 @@
#endif
#include
+#include "XRef.h"
#include "Link.h"
#include "Catalog.h"
#include "Page.h"
class GString;
class BaseStream;
-class XRef;
class OutputDev;
class Links;
class LinkAction;
@@ -33,8 +33,10 @@ class LinkDest;
class PDFDoc {
public:
- PDFDoc(GString *fileName1, GString *userPassword = NULL);
- PDFDoc(BaseStream *str, GString *userPassword = NULL);
+ PDFDoc(GString *fileNameA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, GBool printCommandsA = gFalse);
+ PDFDoc(BaseStream *strA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, GBool printCommandsA = gFalse);
~PDFDoc();
// Was PDF document successfully opened?
@@ -43,6 +45,9 @@ public:
// Get file name.
GString *getFileName() { return fileName; }
+ // Get the xref table.
+ XRef *getXRef() { return xref; }
+
// Get catalog.
Catalog *getCatalog() { return catalog; }
@@ -88,10 +93,14 @@ public:
GBool isEncrypted() { return xref->isEncrypted(); }
// Check various permissions.
- GBool okToPrint() { return xref->okToPrint(); }
- GBool okToChange() { return xref->okToChange(); }
- GBool okToCopy() { return xref->okToCopy(); }
- GBool okToAddNotes() { return xref->okToAddNotes(); }
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToPrint(ignoreOwnerPW); }
+ GBool okToChange(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToChange(ignoreOwnerPW); }
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToCopy(ignoreOwnerPW); }
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToAddNotes(ignoreOwnerPW); }
// Is this document linearized?
GBool isLinearized();
@@ -107,7 +116,7 @@ public:
private:
- GBool setup(GString *userPassword);
+ GBool setup(GString *ownerPassword, GString *userPassword);
void checkHeader();
void getLinks(Page *page);
@@ -118,6 +127,7 @@ private:
XRef *xref;
Catalog *catalog;
Links *links;
+ GBool printCommands;
GBool ok;
};
diff --git a/pdftops/PSOutputDev.cxx b/pdftops/PSOutputDev.cxx
index 84e8ca7c72..b62a23d24b 100644
--- a/pdftops/PSOutputDev.cxx
+++ b/pdftops/PSOutputDev.cxx
@@ -11,7 +11,6 @@
#endif
#include
-#include
#include
#include
#include
@@ -20,6 +19,7 @@
#include "config.h"
#include "Object.h"
#include "Error.h"
+#include "Function.h"
#include "GfxState.h"
#include "GfxFont.h"
#include "FontFile.h"
@@ -38,32 +38,11 @@
#include "ICSupport.h"
#endif
-//------------------------------------------------------------------------
-// Parameters
-//------------------------------------------------------------------------
-
-// Generate Level 1 PostScript?
-GBool psOutLevel1 = gFalse;
-
-// Generate Level 1 separable PostScript?
-GBool psOutLevel1Sep = gFalse;
-
-// Generate Encapsulated PostScript?
-GBool psOutEPS = gFalse;
-
-#if OPI_SUPPORT
-// Generate OPI comments?
-GBool psOutOPI = gFalse;
-#endif
-
-int paperWidth = defPaperWidth;
-int paperHeight = defPaperHeight;
-
//------------------------------------------------------------------------
// PostScript prolog and setup
//------------------------------------------------------------------------
-static const char *prolog[] = {
+static char *prolog[] = {
"/xpdf 75 dict def xpdf begin",
"% PDF special state",
"/pdfDictSize 14 def",
@@ -94,19 +73,83 @@ static const char *prolog[] = {
" /pdfHorizScaling 1 def",
"} def",
"/pdfEndPage { end } def",
+ "% separation convention operators",
+ "/findcmykcustomcolor where {",
+ " pop",
+ "}{",
+ " /findcmykcustomcolor { 5 array astore } def",
+ "} ifelse",
+ "/setcustomcolor where {",
+ " pop",
+ "}{",
+ " /setcustomcolor {",
+ " exch",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval cvx",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace setcolor",
+ " } def",
+ "} ifelse",
+ "/customcolorimage where {",
+ " pop",
+ "}{",
+ " /customcolorimage {",
+ " gsave",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval cvx",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace",
+ " 10 dict begin",
+ " /ImageType 1 def",
+ " /DataSource exch def",
+ " /ImageMatrix exch def",
+ " /BitsPerComponent exch def",
+ " /Height exch def",
+ " /Width exch def",
+ " /Decode [1 0] def",
+ " currentdict end",
+ " image",
+ " grestore",
+ " } def",
+ "} ifelse",
+ "% PDF color state",
"/sCol {",
" pdfLastStroke not {",
" pdfStroke aload length",
- " dup 1 eq { pop setgray }",
- " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse",
+ " dup 1 eq {",
+ " pop setgray",
+ " }{",
+ " dup 3 eq {",
+ " pop setrgbcolor",
+ " }{",
+ " 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " } ifelse",
+ " } ifelse",
" /pdfLastStroke true def /pdfLastFill false def",
" } if",
"} def",
"/fCol {",
" pdfLastFill not {",
" pdfFill aload length",
- " dup 1 eq { pop setgray }",
- " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse",
+ " dup 1 eq {",
+ " pop setgray",
+ " }{",
+ " dup 3 eq {",
+ " pop setrgbcolor",
+ " }{",
+ " 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " } ifelse",
+ " } ifelse",
" /pdfLastFill true def /pdfLastStroke false def",
" } if",
"} def",
@@ -145,6 +188,12 @@ static const char *prolog[] = {
" /pdfLastFill true def /pdfLastStroke false def } def",
"/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
" /pdfLastStroke true def /pdfLastFill false def } def",
+ "/ck { 6 copy 6 array astore /pdfFill exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/CK { 6 copy 6 array astore /pdfStroke exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
"% path segment operators",
"/m { moveto } def",
"/l { lineto } def",
@@ -178,13 +227,10 @@ static const char *prolog[] = {
" pdfFontSize mul pdfHorizScaling mul",
" 1 index stringwidth pdfTextMat idtransform pop",
" sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
- " pdfWordSpacing 0 pdfTextMat dtransform 32",
- " 4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
-#if 0 /* temporary fix until we can figure out why the width is wrong */
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
" 6 5 roll awidthshow",
-#else
- " 6 5 roll show pop pop pop pop pop",
-#endif /* 0 */
" 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
"/TJm { pdfFontSize 0.001 mul mul neg 0",
" pdfTextMat dtransform rmoveto } def",
@@ -216,6 +262,20 @@ static const char *prolog[] = {
" not { pop exit } if",
" (%-EOD-) eq { exit } if } loop",
"} def",
+ "/pdfImSep {",
+ " findcmykcustomcolor exch",
+ " dup /Width get /pdfImBuf1 exch string def",
+ " begin Width Height BitsPerComponent ImageMatrix DataSource end",
+ " /pdfImData exch def",
+ " { pdfImData pdfImBuf1 readstring pop",
+ " 0 1 2 index length 1 sub {",
+ " 1 index exch 2 copy get 255 exch sub put",
+ " } for }",
+ " 6 5 roll customcolorimage",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
"/pdfImM {",
" fCol imagemask",
" { currentfile pdfImBuf readline",
@@ -231,19 +291,19 @@ static const char *prolog[] = {
//------------------------------------------------------------------------
struct PSFont {
- const char *name; // PDF name
- const char *psName; // PostScript name
+ char *name; // PDF name
+ char *psName; // PostScript name
};
struct PSSubstFont {
- const char *psName; // PostScript name
+ char *psName; // PostScript name
double mWidth; // width of 'm' character
};
static PSFont psFonts[] = {
{"Courier", "Courier"},
{"Courier-Bold", "Courier-Bold"},
- {"Courier-Oblique", "Courier-Bold"},
+ {"Courier-Oblique", "Courier-Oblique"},
{"Courier-BoldOblique", "Courier-BoldOblique"},
{"Helvetica", "Helvetica"},
{"Helvetica-Bold", "Helvetica-Bold"},
@@ -273,31 +333,87 @@ static PSSubstFont psSubstFonts[] = {
{"Courier-BoldOblique", 0.600}
};
+//------------------------------------------------------------------------
+// process colors
+//------------------------------------------------------------------------
+
+#define psProcessCyan 1
+#define psProcessMagenta 2
+#define psProcessYellow 4
+#define psProcessBlack 8
+#define psProcessCMYK 15
+
+//------------------------------------------------------------------------
+// PSOutCustomColor
+//------------------------------------------------------------------------
+
+class PSOutCustomColor {
+public:
+
+ PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA);
+ ~PSOutCustomColor();
+
+ double c, m, y, k;
+ GString *name;
+ PSOutCustomColor *next;
+};
+
+PSOutCustomColor::PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA) {
+ c = cA;
+ m = mA;
+ y = yA;
+ k = kA;
+ name = nameA;
+ next = NULL;
+}
+
+PSOutCustomColor::~PSOutCustomColor() {
+ delete name;
+}
+
//------------------------------------------------------------------------
// PSOutputDev
//------------------------------------------------------------------------
-PSOutputDev::PSOutputDev(const char *fileName, Catalog *catalog,
+extern "C" {
+typedef void (*SignalFunc)(int);
+}
+
+PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
int firstPage, int lastPage,
- GBool embedType11, GBool doForm1) {
+ PSOutLevel levelA, PSOutMode modeA, GBool doOPIA,
+ GBool embedType1A, GBool embedTrueTypeA,
+ int paperWidthA, int paperHeightA) {
Page *page;
+ PDFRectangle *box;
Dict *resDict;
FormWidgets *formWidgets;
- const char **p;
+ char **p;
int pg;
Object obj1, obj2;
int i;
// initialize
- embedType1 = embedType11;
- doForm = doForm1;
+ xref = xrefA;
+ level = levelA;
+ mode = modeA;
+ doOPI = doOPIA;
+ embedType1 = embedType1A;
+ embedTrueType = embedTrueTypeA;
+ paperWidth = paperWidthA;
+ paperHeight = paperHeightA;
fontIDs = NULL;
fontFileIDs = NULL;
fontFileNames = NULL;
embFontList = NULL;
f = NULL;
- if (doForm)
+ if (mode == psModeForm) {
lastPage = firstPage;
+ }
+ processColors = 0;
+ customColors = NULL;
// open file or pipe
ok = gTrue;
@@ -308,7 +424,7 @@ PSOutputDev::PSOutputDev(const char *fileName, Catalog *catalog,
fileType = psPipe;
#ifdef HAVE_POPEN
#ifndef WIN32
- signal(SIGPIPE, SIG_IGN);
+ signal(SIGPIPE, (SignalFunc)SIG_IGN);
#endif
if (!(f = popen(fileName + 1, "w"))) {
error(-1, "Couldn't run print command '%s'", fileName);
@@ -344,63 +460,70 @@ PSOutputDev::PSOutputDev(const char *fileName, Catalog *catalog,
embFontList = new GString();
// write header
- if (doForm) {
- writePS("%%!PS-Adobe-3.0 Resource-Form\n");
+ switch (mode) {
+ case psModePS:
+ writePS("%%!PS-Adobe-3.0\n");
writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
writePS("%%%%LanguageLevel: %d\n",
- (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
- if (psOutLevel1Sep) {
- writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
+ (level == psLevel1 || level == psLevel1Sep) ? 1 : 2);
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors: (atend)\n");
+ writePS("%%%%DocumentCustomColors: (atend)\n");
}
+ writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
+ paperWidth, paperHeight);
+ writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
writePS("%%%%EndComments\n");
- page = catalog->getPage(firstPage);
- writePS("32 dict dup begin\n");
- writePS("/BBox [%d %d %d %d] def\n",
- (int)page->getX1(), (int)page->getY1(),
- (int)page->getX2(), (int)page->getY2());
- writePS("/FormType 1 def\n");
- writePS("/Matrix [1 0 0 1 0 0] def\n");
- } else if (psOutEPS) {
+ writePS("%%%%BeginDefaults\n");
+ writePS("%%%%PageMedia: plain\n");
+ writePS("%%%%EndDefaults\n");
+ break;
+ case psModeEPS:
writePS("%%!PS-Adobe-3.0 EPSF-3.0\n");
writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
writePS("%%%%LanguageLevel: %d\n",
- (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
- if (psOutLevel1Sep) {
- writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
+ (level == psLevel1 || level == psLevel1Sep) ? 1 : 2);
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors: (atend)\n");
+ writePS("%%%%DocumentCustomColors: (atend)\n");
}
page = catalog->getPage(firstPage);
+ box = page->getBox();
writePS("%%%%BoundingBox: %d %d %d %d\n",
- (int)floor(page->getX1()), (int)floor(page->getY1()),
- (int)ceil(page->getX2()), (int)ceil(page->getY2()));
- if (floor(page->getX1()) != ceil(page->getX1()) ||
- floor(page->getY1()) != ceil(page->getY1()) ||
- floor(page->getX2()) != ceil(page->getX2()) ||
- floor(page->getY2()) != ceil(page->getY2())) {
+ (int)floor(box->x1), (int)floor(box->y1),
+ (int)ceil(box->x2), (int)ceil(box->y2));
+ if (floor(box->x1) != ceil(box->x1) ||
+ floor(box->y1) != ceil(box->y1) ||
+ floor(box->x2) != ceil(box->x2) ||
+ floor(box->y2) != ceil(box->y2)) {
writePS("%%%%HiResBoundingBox: %g %g %g %g\n",
- page->getX1(), page->getY1(),
- page->getX2(), page->getY2());
+ box->x1, box->y1, box->x2, box->y2);
}
writePS("%%%%DocumentSuppliedResources: (atend)\n");
writePS("%%%%EndComments\n");
- } else {
- writePS("%%!PS-Adobe-3.0\n");
+ break;
+ case psModeForm:
+ writePS("%%!PS-Adobe-3.0 Resource-Form\n");
writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
writePS("%%%%LanguageLevel: %d\n",
- (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
- if (psOutLevel1Sep) {
- writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
+ (level == psLevel1 || level == psLevel1Sep) ? 1 : 2);
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors: (atend)\n");
+ writePS("%%%%DocumentCustomColors: (atend)\n");
}
- writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
- paperWidth, paperHeight);
- writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
writePS("%%%%EndComments\n");
- writePS("%%%%BeginDefaults\n");
- writePS("%%%%PageMedia: plain\n");
- writePS("%%%%EndDefaults\n");
+ page = catalog->getPage(firstPage);
+ box = page->getBox();
+ writePS("32 dict dup begin\n");
+ writePS("/BBox [%d %d %d %d] def\n",
+ (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2);
+ writePS("/FormType 1 def\n");
+ writePS("/Matrix [1 0 0 1 0 0] def\n");
+ break;
}
// write prolog
- if (!doForm) {
+ if (mode != psModeForm) {
writePS("%%%%BeginProlog\n");
}
writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
@@ -408,13 +531,13 @@ PSOutputDev::PSOutputDev(const char *fileName, Catalog *catalog,
writePS("%s\n", *p);
}
writePS("%%%%EndResource\n");
- if (!doForm) {
+ if (mode != psModeForm) {
writePS("%%%%EndProlog\n");
}
// set up fonts and images
type3Warning = gFalse;
- if (doForm) {
+ if (mode == psModeForm) {
// swap the form and xpdf dicts
writePS("xpdf end begin dup begin\n");
} else {
@@ -426,7 +549,7 @@ PSOutputDev::PSOutputDev(const char *fileName, Catalog *catalog,
if ((resDict = page->getResourceDict())) {
setupResources(resDict);
}
- formWidgets = new FormWidgets(page->getAnnots(&obj1));
+ formWidgets = new FormWidgets(xref, page->getAnnots(&obj1));
obj1.free();
for (i = 0; i < formWidgets->getNumWidgets(); ++i) {
if (formWidgets->getWidget(i)->getAppearance(&obj1)->isStream()) {
@@ -440,17 +563,14 @@ PSOutputDev::PSOutputDev(const char *fileName, Catalog *catalog,
}
delete formWidgets;
}
- if (!doForm) {
+ if (mode != psModeForm) {
#if OPI_SUPPORT
- if (psOutOPI) {
+ if (doOPI) {
writePS("/opiMatrix matrix currentmatrix def\n");
}
#endif
- if (!psOutEPS) {
- if (!getenv("PPD") || !getenv("SOFTWARE")) {
- // pdfSetup not used for CUPS filter...
- writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
- }
+ if (mode != psModeEPS) {
+ writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
}
writePS("%%%%EndSetup\n");
}
@@ -466,20 +586,43 @@ PSOutputDev::PSOutputDev(const char *fileName, Catalog *catalog,
}
PSOutputDev::~PSOutputDev() {
+ PSOutCustomColor *cc;
int i;
if (f) {
- if (doForm) {
+ if (mode == psModeForm) {
writePS("/Foo exch /Form defineresource pop\n");
- } else if (psOutEPS) {
+ } else {
writePS("%%%%Trailer\n");
writePS("end\n");
writePS("%%%%DocumentSuppliedResources:\n");
writePS("%s", embFontList->getCString());
- writePS("%%%%EOF\n");
- } else {
- writePS("%%%%Trailer\n");
- writePS("end\n");
+ if (level == psLevel1Sep || level == psLevel2Sep) {
+ writePS("%%%%DocumentProcessColors:");
+ if (processColors & psProcessCyan) {
+ writePS(" Cyan");
+ }
+ if (processColors & psProcessMagenta) {
+ writePS(" Magenta");
+ }
+ if (processColors & psProcessYellow) {
+ writePS(" Yellow");
+ }
+ if (processColors & psProcessBlack) {
+ writePS(" Black");
+ }
+ writePS("\n");
+ writePS("%%%%DocumentCustomColors:");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePS(" (%s)", cc->name->getCString());
+ }
+ writePS("\n");
+ writePS("%%%%CMYKCustomColor:\n");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePS("%%%%+ %g %g %g %g (%s)\n",
+ cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
+ }
+ }
writePS("%%%%EOF\n");
}
if (fileType == psFile) {
@@ -492,7 +635,7 @@ PSOutputDev::~PSOutputDev() {
else if (fileType == psPipe) {
pclose(f);
#ifndef WIN32
- signal(SIGPIPE, SIG_DFL);
+ signal(SIGPIPE, (SignalFunc)SIG_DFL);
#endif
}
#endif
@@ -512,6 +655,11 @@ PSOutputDev::~PSOutputDev() {
}
gfree(fontFileNames);
}
+ while (customColors) {
+ cc = customColors;
+ customColors = cc->next;
+ delete cc;
+ }
}
void PSOutputDev::setupResources(Dict *resDict) {
@@ -546,7 +694,7 @@ void PSOutputDev::setupFonts(Dict *resDict) {
resDict->lookup("Font", &fontDict);
if (fontDict.isDict()) {
- gfxFontDict = new GfxFontDict(fontDict.getDict());
+ gfxFontDict = new GfxFontDict(xref, fontDict.getDict());
for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
font = gfxFontDict->getFont(i);
setupFont(font);
@@ -559,8 +707,8 @@ void PSOutputDev::setupFonts(Dict *resDict) {
void PSOutputDev::setupFont(GfxFont *font) {
Ref fontFileID;
GString *name;
- const char *psName;
- const char *charName;
+ char *psName;
+ char *charName;
double xs, ys;
GBool do16Bit;
int code;
@@ -604,6 +752,13 @@ void PSOutputDev::setupFont(GfxFont *font) {
psName = font->getEmbeddedFontName();
setupEmbeddedType1CFont(font, &fontFileID, psName);
+ // check for embedded TrueType font
+ } else if (embedTrueType && font->getType() == fontTrueType &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = font->getEmbeddedFontName();
+ setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
+
+ // check for Japanese font
} else if (font->is16Bit() && font->getCharSet16() == font16AdobeJapan12) {
psName = "Ryumin-Light-RKSJ";
do16Bit = gTrue;
@@ -673,6 +828,11 @@ void PSOutputDev::setupFont(GfxFont *font) {
writePS((i == 0) ? "[ " : " ");
for (j = 0; j < 8; ++j) {
charName = font->getCharName(i+j);
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
+ charName = "space";
+ }
writePS("/%s", charName ? charName : ".notdef");
}
writePS((i == 256-8) ? "]\n" : "\n");
@@ -681,7 +841,7 @@ void PSOutputDev::setupFont(GfxFont *font) {
}
}
-void PSOutputDev::setupEmbeddedType1Font(Ref *id, const char *psName) {
+void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
static char hexChar[17] = "0123456789abcdef";
Object refObj, strObj, obj1, obj2;
Dict *dict;
@@ -707,7 +867,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, const char *psName) {
// get the font stream and info
refObj.initRef(id->num, id->gen);
- refObj.fetch(&strObj);
+ refObj.fetch(xref, &strObj);
refObj.free();
if (!strObj.isStream()) {
error(-1, "Embedded font file object is not a stream");
@@ -731,12 +891,10 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, const char *psName) {
obj2.free();
// beginning comment
- if (psOutEPS) {
- writePS("%%%%BeginResource: font %s\n", psName);
- embFontList->append("%%+ font ");
- embFontList->append(psName);
- embFontList->append("\n");
- }
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
// copy ASCII portion of font
strObj.streamReset();
@@ -792,9 +950,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, const char *psName) {
writePS("cleartomark\n");
// ending comment
- if (psOutEPS) {
- writePS("%%%%EndResource\n");
- }
+ writePS("%%%%EndResource\n");
err1:
strObj.streamClose();
@@ -803,7 +959,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, const char *psName) {
//~ This doesn't handle .pfb files or binary eexec data (which only
//~ happens in pfb files?).
-void PSOutputDev::setupEmbeddedType1Font(GString *fileName, const char *psName) {
+void PSOutputDev::setupEmbeddedType1Font(GString *fileName, char *psName) {
FILE *fontFile;
int c;
int i;
@@ -824,12 +980,10 @@ void PSOutputDev::setupEmbeddedType1Font(GString *fileName, const char *psName)
fontFileNames[fontFileNameLen++] = fileName->copy();
// beginning comment
- if (psOutEPS) {
- writePS("%%%%BeginResource: font %s\n", psName);
- embFontList->append("%%+ font ");
- embFontList->append(psName);
- embFontList->append("\n");
- }
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
// copy the font file
if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
@@ -841,14 +995,12 @@ void PSOutputDev::setupEmbeddedType1Font(GString *fileName, const char *psName)
fclose(fontFile);
// ending comment
- if (psOutEPS) {
- writePS("%%%%EndResource\n");
- }
+ writePS("%%%%EndResource\n");
}
void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
- const char *psName) {
- const char *fontBuf;
+ char *psName) {
+ char *fontBuf;
int fontLen;
Type1CFontConverter *cvt;
int i;
@@ -868,31 +1020,65 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
fontFileIDs[fontFileIDLen++] = *id;
// beginning comment
- if (psOutEPS) {
- writePS("%%%%BeginResource: font %s\n", psName);
- embFontList->append("%%+ font ");
- embFontList->append(psName);
- embFontList->append("\n");
- }
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
// convert it to a Type 1 font
- fontBuf = font->readEmbFontFile(&fontLen);
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
cvt = new Type1CFontConverter(fontBuf, fontLen, f);
cvt->convert();
delete cvt;
- gfree((void *)fontBuf);
+ gfree(fontBuf);
// ending comment
- if (psOutEPS) {
- writePS("%%%%EndResource\n");
+ writePS("%%%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
+ char *psName) {
+ char *fontBuf;
+ int fontLen;
+ TrueTypeFontFile *ttFile;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
}
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePS("%%%%BeginResource: font %s\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName);
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ ttFile = new TrueTypeFontFile(fontBuf, fontLen);
+ ttFile->convertToType42(psName, font->getEncoding(), f);
+ delete ttFile;
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%%%EndResource\n");
}
void PSOutputDev::setupImages(Dict *resDict) {
Object xObjDict, xObj, xObjRef, subtypeObj;
int i;
- if (!doForm) {
+ if (mode != psModeForm) {
return;
}
@@ -1006,24 +1192,9 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
void PSOutputDev::startPage(int pageNum, GfxState *state) {
int x1, y1, x2, y2, width, height, t;
- if (doForm) {
-
- writePS("/PaintProc {\n");
- writePS("begin xpdf begin\n");
- writePS("pdfStartPage\n");
- tx = ty = 0;
- xScale = yScale = 1;
- landscape = gFalse;
-
- } else if (psOutEPS) {
-
- writePS("pdfStartPage\n");
- tx = ty = 0;
- xScale = yScale = 1;
- landscape = gFalse;
-
- } else {
+ switch (mode) {
+ case psModePS:
writePS("%%%%Page: %d %d\n", pageNum, seqPage);
writePS("%%%%BeginPageSetup\n");
@@ -1073,11 +1244,28 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
writePS("%%%%EndPageSetup\n");
++seqPage;
+ break;
+
+ case psModeEPS:
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ xScale = yScale = 1;
+ landscape = gFalse;
+ break;
+
+ case psModeForm:
+ writePS("/PaintProc {\n");
+ writePS("begin xpdf begin\n");
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ xScale = yScale = 1;
+ landscape = gFalse;
+ break;
}
}
void PSOutputDev::endPage() {
- if (doForm) {
+ if (mode == psModeForm) {
writePS("pdfEndPage\n");
writePS("end end\n");
writePS("} def\n");
@@ -1090,21 +1278,15 @@ void PSOutputDev::endPage() {
}
void PSOutputDev::saveState(GfxState *state) {
- (void)state;
-
writePS("q\n");
}
void PSOutputDev::restoreState(GfxState *state) {
- (void)state;
-
writePS("Q\n");
}
void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
double m21, double m22, double m31, double m32) {
- (void)state;
-
writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
}
@@ -1141,39 +1323,134 @@ void PSOutputDev::updateLineWidth(GfxState *state) {
}
void PSOutputDev::updateFillColor(GfxState *state) {
+ GfxColor color;
+ double gray;
GfxRGB rgb;
GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
- if (psOutLevel1Sep) {
+ switch (level) {
+ case psLevel1:
+ state->getFillGray(&gray);
+ writePS("%g g\n", gray);
+ break;
+ case psLevel1Sep:
state->getFillCMYK(&cmyk);
writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
- } else {
- state->getFillRGB(&rgb);
- if (rgb.r == rgb.g && rgb.g == rgb.b) {
- writePS("%g g\n", rgb.r);
+ break;
+ case psLevel2:
+ if (state->getFillColorSpace()->getMode() == csDeviceCMYK) {
+ state->getFillCMYK(&cmyk);
+ writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ } else {
+ state->getFillRGB(&rgb);
+ if (rgb.r == rgb.g && rgb.g == rgb.b) {
+ writePS("%g g\n", rgb.r);
+ } else {
+ writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
+ }
+ }
+ break;
+ case psLevel2Sep:
+ if (state->getFillColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePS("%g %g %g %g %g (%s) ck\n",
+ state->getFillColor()->c[0],
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->getCString());
+ addCustomColor(sepCS);
} else {
- writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
+ state->getFillCMYK(&cmyk);
+ writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
}
+ break;
}
}
void PSOutputDev::updateStrokeColor(GfxState *state) {
+ GfxColor color;
+ double gray;
GfxRGB rgb;
GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
- if (psOutLevel1Sep) {
+ switch (level) {
+ case psLevel1:
+ state->getStrokeGray(&gray);
+ writePS("%g G\n", gray);
+ break;
+ case psLevel1Sep:
state->getStrokeCMYK(&cmyk);
writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
- } else {
- state->getStrokeRGB(&rgb);
- if (rgb.r == rgb.g && rgb.g == rgb.b) {
- writePS("%g G\n", rgb.r);
+ break;
+ case psLevel2:
+ if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) {
+ state->getStrokeCMYK(&cmyk);
+ writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
} else {
- writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
+ state->getStrokeRGB(&rgb);
+ if (rgb.r == rgb.g && rgb.g == rgb.b) {
+ writePS("%g G\n", rgb.r);
+ } else {
+ writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
+ }
}
+ break;
+ case psLevel2Sep:
+ if (state->getStrokeColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePS("%g %g %g %g %g (%s) CK\n",
+ state->getStrokeColor()->c[0],
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->getCString());
+ addCustomColor(sepCS);
+ } else {
+ state->getStrokeCMYK(&cmyk);
+ writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ }
+ break;
}
}
+void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
+ if (c > 0) {
+ processColors |= psProcessCyan;
+ }
+ if (m > 0) {
+ processColors |= psProcessMagenta;
+ }
+ if (y > 0) {
+ processColors |= psProcessYellow;
+ }
+ if (k > 0) {
+ processColors |= psProcessBlack;
+ }
+}
+
+void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
+ PSOutCustomColor *cc;
+ GfxColor color;
+ GfxCMYK cmyk;
+
+ for (cc = customColors; cc; cc = cc->next) {
+ if (!cc->name->cmp(sepCS->getName())) {
+ return;
+ }
+ }
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->copy());
+ cc->next = customColors;
+ customColors = cc;
+}
+
void PSOutputDev::updateFont(GfxState *state) {
if (state->getFont()) {
writePS("/F%d_%d %g Tf\n",
@@ -1215,8 +1492,6 @@ void PSOutputDev::updateTextPos(GfxState *state) {
}
void PSOutputDev::updateTextShift(GfxState *state, double shift) {
- (void)state;
-
writePS("%g TJm\n", shift);
}
@@ -1311,13 +1586,9 @@ void PSOutputDev::drawString(GfxState *state, GString *s) {
}
void PSOutputDev::drawString16(GfxState *state, GString *s) {
-#if defined(JAPANESE_SUPPORT) || defined(CHINESE_SUPPORT)
int c1, c2;
double w;
int i;
-#else
- (void)s;
-#endif /* JAPANESE_SUPPORT || CHINESE_SUPPORT */
// check for invisible text -- this is used by Acrobat Capture
if ((state->getRender() & 3) == 3)
@@ -1360,10 +1631,8 @@ void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
GBool inlineImg) {
int len;
- (void)state;
-
len = height * ((width + 7) / 8);
- if (psOutLevel1 || psOutLevel1Sep) {
+ if (level == psLevel1 || level == psLevel1Sep) {
doImageL1(NULL, invert, inlineImg, str, width, height, len);
} else {
doImageL2(ref, NULL, invert, inlineImg, str, width, height, len);
@@ -1372,20 +1641,23 @@ void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
- GBool inlineImg) {
+ int *maskColors, GBool inlineImg) {
int len;
- (void)state;
-
len = height * ((width * colorMap->getNumPixelComps() *
colorMap->getBits() + 7) / 8);
- if (psOutLevel1) {
+ switch (level) {
+ case psLevel1:
doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
- } else if (psOutLevel1Sep) {
+ break;
+ case psLevel1Sep:
//~ handle indexed, separation, ... color spaces
doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
- } else {
+ break;
+ case psLevel2:
+ case psLevel2Sep:
doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
}
}
@@ -1397,9 +1669,6 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
double gray;
int x, y, i;
- (void)inlineImg;
- (void)len;
-
// width, height, matrix, bits per component
if (colorMap) {
writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
@@ -1518,6 +1787,9 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
GString *s;
int n, numComps;
GBool useRLE, useA85;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
int c;
int i;
@@ -1528,7 +1800,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
}
// set up to use the array created by setupImages()
- if (doForm && !inlineImg) {
+ if (mode == psModeForm && !inlineImg) {
writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
}
@@ -1565,7 +1837,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
}
- if (doForm) {
+ if (mode == psModeForm) {
if (inlineImg) {
@@ -1606,26 +1878,32 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
useRLE = gFalse;
useA85 = str->isBinary();
}
- if (useA85)
+ if (useA85) {
writePS(" /ASCII85Decode filter\n");
- if (useRLE)
+ }
+ if (useRLE) {
writePS(" /RunLengthDecode filter\n");
- else
+ } else {
writePS("%s", s->getCString());
- if (s)
+ }
+ if (s) {
delete s;
+ }
// cut off inline image streams at appropriate length
- if (inlineImg)
+ if (inlineImg) {
str = new FixedLengthEncoder(str, len);
- else if (!useRLE)
+ } else if (!useRLE) {
str = str->getBaseStream();
+ }
// add RunLengthEncode and ASCII85 encode filters
- if (useRLE)
+ if (useRLE) {
str = new RunLengthEncoder(str);
- if (useA85)
+ }
+ if (useA85) {
str = new ASCII85Encoder(str);
+ }
// end of image dictionary
writePS(">>\n");
@@ -1650,12 +1928,22 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
writePS("%%%%BeginData: %d Hex Bytes\n", n);
}
#endif
- writePS("%s\n", colorMap ? "pdfIm" : "pdfImM");
+ if (level == psLevel2Sep && colorMap &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ color.c[0] = 1;
+ sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
+ sepCS->getCMYK(&color, &cmyk);
+ writePS("%g %g %g %g (%s) pdfImSep\n",
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k, sepCS->getName()->getCString());
+ } else {
+ writePS("%s\n", colorMap ? "pdfIm" : "pdfImM");
+ }
// copy the stream data
str->reset();
- while ((c = str->getChar()) != EOF)
+ while ((c = str->getChar()) != EOF) {
fputc(c, f);
+ }
// add newline and trailer to the end
fputc('\n', f);
@@ -1667,8 +1955,9 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
#endif
// delete encoders
- if (useRLE || useA85)
+ if (useRLE || useA85) {
delete str;
+ }
}
}
@@ -1679,7 +1968,9 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
GfxIndexedColorSpace *indexedCS;
GfxSeparationColorSpace *separationCS;
Guchar *lookup;
- double x[1], y[gfxColorMaxComps];
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ GfxColor color;
+ GfxCMYK cmyk;
int n, numComps;
int i, j, k;
@@ -1687,6 +1978,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
case csDeviceGray:
writePS("/DeviceGray");
+ processColors |= psProcessBlack;
break;
case csCalGray:
@@ -1703,10 +1995,12 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
calGrayCS->getBlackX(), calGrayCS->getBlackY(),
calGrayCS->getBlackZ());
writePS(">>]");
+ processColors |= psProcessBlack;
break;
case csDeviceRGB:
writePS("/DeviceRGB");
+ processColors |= psProcessCMYK;
break;
case csCalRGB:
@@ -1728,10 +2022,12 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
calRGBCS->getBlackX(), calRGBCS->getBlackY(),
calRGBCS->getBlackZ());
writePS(">>]");
+ processColors |= psProcessCMYK;
break;
case csDeviceCMYK:
writePS("/DeviceCMYK");
+ processColors |= psProcessCMYK;
break;
case csLab:
@@ -1757,6 +2053,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
writePS(" /BlackPoint [%g %g %g]\n",
labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
writePS(">>]");
+ processColors |= psProcessCMYK;
break;
case csICCBased:
@@ -1777,6 +2074,9 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
for (k = 0; k < numComps; ++k) {
writePS("%02x", lookup[j * numComps + k]);
}
+ color.c[0] = j;
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
}
writePS("\n");
}
@@ -1788,7 +2088,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
//~ separation color space, with the specified alternate color
//~ space and tint transform
separationCS = (GfxSeparationColorSpace *)colorSpace;
- writePS(" [/Indexed ");
+ writePS("[/Indexed ");
dumpColorSpaceL2(separationCS->getAlt());
writePS(" 255 <\n");
numComps = separationCS->getAlt()->getNComps();
@@ -1804,6 +2104,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
writePS("\n");
}
writePS(">]");
+ addCustomColor(separationCS);
break;
case csDeviceN:
@@ -1822,7 +2123,7 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
Object dict;
- if (psOutOPI) {
+ if (doOPI) {
opiDict->lookup("2.0", &dict);
if (dict.isDict()) {
opiBegin20(state, dict.getDict());
@@ -2184,7 +2485,7 @@ void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
Object dict;
- if (psOutOPI) {
+ if (doOPI) {
opiDict->lookup("2.0", &dict);
if (dict.isDict()) {
writePS("%%%%EndIncludedImage\n");
diff --git a/pdftops/PSOutputDev.h b/pdftops/PSOutputDev.h
index 62dce66115..81279be4ac 100644
--- a/pdftops/PSOutputDev.h
+++ b/pdftops/PSOutputDev.h
@@ -21,32 +21,25 @@
class GfxPath;
class GfxFont;
class GfxColorSpace;
+class GfxSeparationColorSpace;
+class PSOutCustomColor;
//------------------------------------------------------------------------
-// Parameters
+// PSOutputDev
//------------------------------------------------------------------------
-// Generate Level 1 PostScript?
-extern GBool psOutLevel1;
-
-// Generate Level 1 separable PostScript?
-extern GBool psOutLevel1Sep;
-
-// Generate Encapsulated PostScript?
-extern GBool psOutEPS;
-
-#if OPI_SUPPORT
-// Generate OPI comments?
-extern GBool psOutOPI;
-#endif
-
-// Paper size.
-extern int paperWidth;
-extern int paperHeight;
+enum PSOutLevel {
+ psLevel1,
+ psLevel1Sep,
+ psLevel2,
+ psLevel2Sep
+};
-//------------------------------------------------------------------------
-// PSOutputDev
-//------------------------------------------------------------------------
+enum PSOutMode {
+ psModePS,
+ psModeEPS,
+ psModeForm
+};
enum PSFileType {
psFile, // write to file
@@ -58,9 +51,11 @@ class PSOutputDev: public OutputDev {
public:
// Open a PostScript output file, and write the prolog.
- PSOutputDev(const char *fileName, Catalog *catalog,
+ PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
int firstPage, int lastPage,
- GBool embedType11, GBool doForm1);
+ PSOutLevel levelA, PSOutMode modeA, GBool doOPIA,
+ GBool embedType1A, GBool embedTrueTypeA,
+ int paperWidthA, int paperHeightA);
// Destructor -- writes the trailer and closes the file.
virtual ~PSOutputDev();
@@ -131,7 +126,7 @@ public:
GBool inlineImg);
virtual void drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
- GBool inlineImg);
+ int *maskColors, GBool inlineImg);
#if OPI_SUPPORT
//----- OPI functions
@@ -144,11 +139,14 @@ private:
void setupResources(Dict *resDict);
void setupFonts(Dict *resDict);
void setupFont(GfxFont *font);
- void setupEmbeddedType1Font(Ref *id, const char *psName);
- void setupEmbeddedType1Font(GString *fileName, const char *psName);
- void setupEmbeddedType1CFont(GfxFont *font, Ref *id, const char *psName);
+ void setupEmbeddedType1Font(Ref *id, char *psName);
+ void setupEmbeddedType1Font(GString *fileName, char *psName);
+ void setupEmbeddedType1CFont(GfxFont *font, Ref *id, char *psName);
+ void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, char *psName);
void setupImages(Dict *resDict);
void setupImage(Ref id, Stream *str);
+ void addProcessColor(double c, double m, double y, double k);
+ void addCustomColor(GfxSeparationColorSpace *sepCS);
void doPath(GfxPath *path);
void doImageL1(GfxImageColorMap *colorMap,
GBool invert, GBool inlineImg,
@@ -160,21 +158,30 @@ private:
GBool invert, GBool inlineImg,
Stream *str, int width, int height, int len);
void dumpColorSpaceL2(GfxColorSpace *colorSpace);
+#if OPI_SUPPORT
void opiBegin20(GfxState *state, Dict *dict);
void opiBegin13(GfxState *state, Dict *dict);
void opiTransform(GfxState *state, double x0, double y0,
double *x1, double *y1);
GBool getFileSpec(Object *fileSpec, Object *fileName);
+#endif
void writePS(const char *fmt, ...);
void writePSString(GString *s);
+ PSOutLevel level; // PostScript level (1, 2, separation)
+ PSOutMode mode; // PostScript mode (PS, EPS, form)
+ GBool doOPI; // generate OPI comments?
GBool embedType1; // embed Type 1 fonts?
- GBool doForm; // generate a form?
+ GBool embedTrueType; // embed TrueType fonts?
+ int paperWidth; // width of paper, in pts
+ int paperHeight; // height of paper, in pts
FILE *f; // PostScript file
PSFileType fileType; // file / pipe / stdout
int seqPage; // current sequential page number
+ XRef *xref; // the xref table for this PDF file
+
Ref *fontIDs; // list of object IDs of all used fonts
int fontIDLen; // number of entries in fontIDs array
int fontIDSize; // size of fontIDs array
@@ -191,6 +198,10 @@ private:
GString *embFontList; // resource comments for embedded fonts
+ int processColors; // used process colors
+ PSOutCustomColor // used custom colors
+ *customColors;
+
#if OPI_SUPPORT
int opi13Nest; // nesting level of OPI 1.3 objects
int opi20Nest; // nesting level of OPI 2.0 objects
diff --git a/pdftops/Page.cxx b/pdftops/Page.cxx
index c2ac6b190b..975fcf1b6d 100644
--- a/pdftops/Page.cxx
+++ b/pdftops/Page.cxx
@@ -31,97 +31,68 @@
//------------------------------------------------------------------------
PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
- Object obj1, obj2;
+ Object obj1;
double w, h;
// get old/default values
if (attrs) {
- x1 = attrs->x1;
- y1 = attrs->y1;
- x2 = attrs->x2;
- y2 = attrs->y2;
- cropX1 = attrs->cropX1;
- cropY1 = attrs->cropY1;
- cropX2 = attrs->cropX2;
- cropY2 = attrs->cropY2;
+ mediaBox = attrs->mediaBox;
+ cropBox = attrs->cropBox;
+ haveCropBox = attrs->haveCropBox;
rotate = attrs->rotate;
attrs->resources.copy(&resources);
} else {
// set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
// but some (non-compliant) PDF files don't specify a MediaBox
- x1 = 0;
- y1 = 0;
- x2 = 612;
- y2 = 792;
- cropX1 = cropY1 = cropX2 = cropY2 = 0;
+ mediaBox.x1 = 0;
+ mediaBox.y1 = 0;
+ mediaBox.x2 = 612;
+ mediaBox.y2 = 792;
+ cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
+ haveCropBox = gFalse;
rotate = 0;
resources.initNull();
}
// media box
- dict->lookup("MediaBox", &obj1);
- if (obj1.isArray() && obj1.arrayGetLength() == 4) {
- obj1.arrayGet(0, &obj2);
- if (obj2.isNum())
- x1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(1, &obj2);
- if (obj2.isNum())
- y1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2, &obj2);
- if (obj2.isNum())
- x2 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(3, &obj2);
- if (obj2.isNum())
- y2 = obj2.getNum();
- obj2.free();
- }
- obj1.free();
+ readBox(dict, "MediaBox", &mediaBox);
// crop box
- dict->lookup("CropBox", &obj1);
- if (obj1.isArray() && obj1.arrayGetLength() == 4) {
- obj1.arrayGet(0, &obj2);
- if (obj2.isNum())
- cropX1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(1, &obj2);
- if (obj2.isNum())
- cropY1 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(2, &obj2);
- if (obj2.isNum())
- cropX2 = obj2.getNum();
- obj2.free();
- obj1.arrayGet(3, &obj2);
- if (obj2.isNum())
- cropY2 = obj2.getNum();
- obj2.free();
- }
- obj1.free();
+ cropBox = mediaBox;
+ haveCropBox = readBox(dict, "CropBox", &cropBox);
// if the MediaBox is excessively larger than the CropBox,
// just use the CropBox
limitToCropBox = gFalse;
- w = 0.25 * (cropX2 - cropX1);
- h = 0.25 * (cropY2 - cropY1);
- if (cropX2 > cropX1 &&
- ((cropX1 - x1) + (x2 - cropX2) > w ||
- (cropY1 - y1) + (y2 - cropY2) > h)) {
- limitToCropBox = gTrue;
+ if (haveCropBox) {
+ w = 0.25 * (cropBox.x2 - cropBox.x1);
+ h = 0.25 * (cropBox.y2 - cropBox.y1);
+ if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w ||
+ (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) {
+ limitToCropBox = gTrue;
+ }
}
+ // other boxes
+ bleedBox = cropBox;
+ readBox(dict, "BleedBox", &bleedBox);
+ trimBox = cropBox;
+ readBox(dict, "TrimBox", &trimBox);
+ artBox = cropBox;
+ readBox(dict, "ArtBox", &artBox);
+
// rotate
dict->lookup("Rotate", &obj1);
- if (obj1.isInt())
+ if (obj1.isInt()) {
rotate = obj1.getInt();
+ }
obj1.free();
- while (rotate < 0)
+ while (rotate < 0) {
rotate += 360;
- while (rotate >= 360)
+ }
+ while (rotate >= 360) {
rotate -= 360;
+ }
// resource dictionary
dict->lookup("Resources", &obj1);
@@ -136,17 +107,66 @@ PageAttrs::~PageAttrs() {
resources.free();
}
+GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
+ PDFRectangle tmp;
+ Object obj1, obj2;
+ GBool ok;
+
+ dict->lookup(key, &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ ok = gTrue;
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isNum()) {
+ tmp.x1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ if (obj2.isNum()) {
+ tmp.y1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ if (obj2.isNum()) {
+ tmp.x2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ if (obj2.isNum()) {
+ tmp.y2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ if (ok) {
+ *box = tmp;
+ }
+ } else {
+ ok = gFalse;
+ }
+ obj1.free();
+ return ok;
+}
+
//------------------------------------------------------------------------
// Page
//------------------------------------------------------------------------
-Page::Page(int num1, Dict *pageDict, PageAttrs *attrs1) {
+Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA,
+ GBool printCommandsA) {
ok = gTrue;
- num = num1;
+ xref = xrefA;
+ num = numA;
+ printCommands = printCommandsA;
// get attributes
- attrs = attrs1;
+ attrs = attrsA;
// annotations
pageDict->lookupNF("Annots", &annots);
@@ -185,18 +205,22 @@ Page::~Page() {
void Page::display(OutputDev *out, double dpi, int rotate,
Links *links, Catalog *catalog) {
#ifndef PDF_PARSER_ONLY
+ PDFRectangle *box, *cropBox;
Gfx *gfx;
Object obj;
Link *link;
int i;
FormWidgets *formWidgets;
+ box = getBox();
+ cropBox = getCropBox();
+
if (printCommands) {
printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
- getX1(), getY1(), getX2(), getY2());
+ box->x1, box->y1, box->x2, box->y2);
if (isCropped()) {
printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
- getCropX1(), getCropY1(), getCropX2(), getCropY2());
+ cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
}
printf("***** Rotate = %d\n", attrs->getRotate());
}
@@ -207,10 +231,9 @@ void Page::display(OutputDev *out, double dpi, int rotate,
} else if (rotate < 0) {
rotate += 360;
}
- gfx = new Gfx(out, num, attrs->getResourceDict(),
- dpi, getX1(), getY1(), getX2(), getY2(), isCropped(),
- getCropX1(), getCropY1(), getCropX2(), getCropY2(), rotate);
- contents.fetch(&obj);
+ gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
+ dpi, box, isCropped(), cropBox, rotate, printCommands);
+ contents.fetch(xref, &obj);
if (!obj.isNull()) {
gfx->display(&obj);
}
@@ -227,7 +250,7 @@ void Page::display(OutputDev *out, double dpi, int rotate,
// draw AcroForm widgets
//~ need to reset CTM ???
- formWidgets = new FormWidgets(annots.fetch(&obj));
+ formWidgets = new FormWidgets(xref, annots.fetch(xref, &obj));
obj.free();
if (printCommands && formWidgets->getNumWidgets() > 0) {
printf("***** AcroForm widgets\n");
diff --git a/pdftops/Page.h b/pdftops/Page.h
index a144d2cfa7..a40974cfc4 100644
--- a/pdftops/Page.h
+++ b/pdftops/Page.h
@@ -21,6 +21,12 @@ class OutputDev;
class Links;
class Catalog;
+//------------------------------------------------------------------------
+
+struct PDFRectangle {
+ double x1, y1, x2, y2;
+};
+
//------------------------------------------------------------------------
// PageAttrs
//------------------------------------------------------------------------
@@ -37,24 +43,28 @@ public:
~PageAttrs();
// Accessors.
- double getX1() { return limitToCropBox ? cropX1 : x1; }
- double getY1() { return limitToCropBox ? cropY1 : y1; }
- double getX2() { return limitToCropBox ? cropX2 : x2; }
- double getY2() { return limitToCropBox ? cropY2 : y2; }
- GBool isCropped() { return cropX2 > cropX1; }
- double getCropX1() { return cropX1; }
- double getCropY1() { return cropY1; }
- double getCropX2() { return cropX2; }
- double getCropY2() { return cropY2; }
+ PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; }
+ PDFRectangle *getMediaBox() { return &mediaBox; }
+ PDFRectangle *getCropBox() { return &cropBox; }
+ GBool isCropped() { return haveCropBox; }
+ PDFRectangle *getBleedBox() { return &bleedBox; }
+ PDFRectangle *getTrimBox() { return &trimBox; }
+ PDFRectangle *getArtBox() { return &artBox; }
int getRotate() { return rotate; }
Dict *getResourceDict()
{ return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
private:
- double x1, y1, x2, y2;
- double cropX1, cropY1, cropX2, cropY2;
+ GBool readBox(Dict *dict, char *key, PDFRectangle *box);
+
+ PDFRectangle mediaBox;
+ PDFRectangle cropBox;
+ GBool haveCropBox;
GBool limitToCropBox;
+ PDFRectangle bleedBox;
+ PDFRectangle trimBox;
+ PDFRectangle artBox;
int rotate;
Object resources;
};
@@ -67,7 +77,8 @@ class Page {
public:
// Constructor.
- Page(int num1, Dict *pageDict, PageAttrs *attrs1);
+ Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA,
+ GBool printCommandsA);
// Destructor.
~Page();
@@ -76,27 +87,25 @@ public:
GBool isOk() { return ok; }
// Get page parameters.
- double getX1() { return attrs->getX1(); }
- double getY1() { return attrs->getY1(); }
- double getX2() { return attrs->getX2(); }
- double getY2() { return attrs->getY2(); }
+ PDFRectangle *getBox() { return attrs->getBox(); }
+ PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
+ PDFRectangle *getCropBox() { return attrs->getCropBox(); }
GBool isCropped() { return attrs->isCropped(); }
- double getCropX1() { return attrs->getCropX1(); }
- double getCropY1() { return attrs->getCropY1(); }
- double getCropX2() { return attrs->getCropX2(); }
- double getCropY2() { return attrs->getCropY2(); }
- double getWidth() { return attrs->getX2() - attrs->getX1(); }
- double getHeight() { return attrs->getY2() - attrs->getY1(); }
+ double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; }
+ double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; }
+ PDFRectangle *getBleedBox() { return attrs->getBleedBox(); }
+ PDFRectangle *getTrimBox() { return attrs->getTrimBox(); }
+ PDFRectangle *getArtBox() { return attrs->getArtBox(); }
int getRotate() { return attrs->getRotate(); }
// Get resource dictionary.
Dict *getResourceDict() { return attrs->getResourceDict(); }
// Get annotations array.
- Object *getAnnots(Object *obj) { return annots.fetch(obj); }
+ Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); }
// Get contents.
- Object *getContents(Object *obj) { return contents.fetch(obj); }
+ Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
// Display a page.
void display(OutputDev *out, double dpi, int rotate,
@@ -104,10 +113,12 @@ public:
private:
+ XRef *xref; // the xref table for this PDF file
int num; // page number
PageAttrs *attrs; // page attributes
Object annots; // annotations array
Object contents; // page contents
+ GBool printCommands; // print the drawing commands (for debugging)
GBool ok; // true if page is valid
};
diff --git a/pdftops/Params.cxx b/pdftops/Params.cxx
index efed572435..8536da20d3 100644
--- a/pdftops/Params.cxx
+++ b/pdftops/Params.cxx
@@ -16,35 +16,38 @@
#include "gfile.h"
#include "Params.h"
-const char **fontPath = NULL;
+char **fontPath = NULL;
static int fontPathLen, fontPathSize;
DevFontMapEntry *devFontMap = NULL;
static int devFontMapLen, devFontMapSize;
-void initParams(const char *configFile) {
+void initParams(char *userConfigFile, char *sysConfigFile) {
GString *fileName;
FILE *f;
char buf[256];
char *p, *q;
// initialize font path and font map
- fontPath = (const char **)gmalloc((fontPathSize = 8) * sizeof(const char *));
+ fontPath = (char **)gmalloc((fontPathSize = 8) * sizeof(char *));
fontPath[fontPathLen = 0] = NULL;
devFontMap = (DevFontMapEntry *)gmalloc((devFontMapSize = 8) *
sizeof(DevFontMapEntry));
devFontMap[devFontMapLen = 0].pdfFont = NULL;
// read config file
- fileName = appendToPath(getHomeDir(), configFile);
- if ((f = fopen(fileName->getCString(), "r"))) {
+ fileName = appendToPath(getHomeDir(), userConfigFile);
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ f = fopen(sysConfigFile, "r");
+ }
+ if (f) {
while (fgets(buf, sizeof(buf)-1, f)) {
buf[sizeof(buf)-1] = '\0';
p = strtok(buf, " \t\n\r");
if (p && !strcmp(p, "fontpath")) {
if (fontPathLen+1 >= fontPathSize)
- fontPath = (const char **)
- grealloc(fontPath, (fontPathSize += 8) * sizeof(const char *));
+ fontPath = (char **)
+ grealloc(fontPath, (fontPathSize += 8) * sizeof(char *));
p = strtok(NULL, " \t\n\r");
fontPath[fontPathLen++] = copyString(p);
} else if (p && !strcmp(p, "fontmap")) {
@@ -74,14 +77,14 @@ void freeParams() {
if (fontPath) {
for (i = 0; i < fontPathLen; ++i)
- gfree((void *)fontPath[i]);
- gfree((void *)fontPath);
+ gfree(fontPath[i]);
+ gfree(fontPath);
}
if (devFontMap) {
for (i = 0; i < devFontMapLen; ++i) {
- gfree((void *)devFontMap[i].pdfFont);
- gfree((void *)devFontMap[i].devFont);
+ gfree(devFontMap[i].pdfFont);
+ gfree(devFontMap[i].devFont);
}
- gfree((void *)devFontMap);
+ gfree(devFontMap);
}
}
diff --git a/pdftops/Params.h b/pdftops/Params.h
index 2c5936a3f4..1d8ce38282 100644
--- a/pdftops/Params.h
+++ b/pdftops/Params.h
@@ -9,27 +9,28 @@
#ifndef PARAMS_H
#define PARAMS_H
-// Print commands as they're executed.
-extern GBool printCommands;
+#include "gtypes.h"
// If this is set, error messages will be silently discarded.
extern GBool errQuiet;
// Font search path.
-extern const char **fontPath;
+extern char **fontPath;
// Mapping from PDF font name to device font name.
struct DevFontMapEntry {
- const char *pdfFont;
- const char *devFont;
+ char *pdfFont;
+ char *devFont;
};
extern DevFontMapEntry *devFontMap;
//------------------------------------------------------------------------
-// Initialize font path and font map, and read configuration file,
-// if present.
-extern void initParams(const char *configFile);
+// Initialize font path and font map, and read configuration file. If
+// exists, read it; else if exists,
+// read it. is relative to the user's home
+// directory; should be an absolute path.
+extern void initParams(char *userConfigFile, char *sysConfigFile);
// Free memory used for font path and font map.
extern void freeParams();
diff --git a/pdftops/Parser.cxx b/pdftops/Parser.cxx
index 6ad0c5a781..57ba05061e 100644
--- a/pdftops/Parser.cxx
+++ b/pdftops/Parser.cxx
@@ -21,8 +21,9 @@
#include "Decrypt.h"
#endif
-Parser::Parser(Lexer *lexer1) {
- lexer = lexer1;
+Parser::Parser(XRef *xrefA, Lexer *lexerA) {
+ xref = xrefA;
+ lexer = lexerA;
inlineImg = 0;
lexer->getObj(&buf1);
lexer->getObj(&buf2);
@@ -36,7 +37,8 @@ Parser::~Parser() {
#ifndef NO_DECRYPTION
Object *Parser::getObj(Object *obj,
- Guchar *fileKey, int objNum, int objGen) {
+ Guchar *fileKey, int keyLength,
+ int objNum, int objGen) {
#else
Object *Parser::getObj(Object *obj) {
#endif
@@ -63,10 +65,10 @@ Object *Parser::getObj(Object *obj) {
// array
if (buf1.isCmd("[")) {
shift();
- obj->initArray();
+ obj->initArray(xref);
while (!buf1.isCmd("]") && !buf1.isEOF())
#ifndef NO_DECRYPTION
- obj->arrayAdd(getObj(&obj2, fileKey, objNum, objGen));
+ obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen));
#else
obj->arrayAdd(getObj(&obj2));
#endif
@@ -77,7 +79,7 @@ Object *Parser::getObj(Object *obj) {
// dictionary or stream
} else if (buf1.isCmd("<<")) {
shift();
- obj->initDict();
+ obj->initDict(xref);
while (!buf1.isCmd(">>") && !buf1.isEOF()) {
if (!buf1.isName()) {
error(getPos(), "Dictionary key must be a name object");
@@ -88,7 +90,7 @@ Object *Parser::getObj(Object *obj) {
if (buf1.isEOF() || buf1.isError())
break;
#ifndef NO_DECRYPTION
- obj->dictAdd(key, getObj(&obj2, fileKey, objNum, objGen));
+ obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
#else
obj->dictAdd(key, getObj(&obj2));
#endif
@@ -101,7 +103,8 @@ Object *Parser::getObj(Object *obj) {
obj->initStream(str);
#ifndef NO_DECRYPTION
if (fileKey) {
- str->getBaseStream()->doDecryption(fileKey, objNum, objGen);
+ str->getBaseStream()->doDecryption(fileKey, keyLength,
+ objNum, objGen);
}
#endif
} else {
@@ -129,7 +132,7 @@ Object *Parser::getObj(Object *obj) {
} else if (buf1.isString() && fileKey) {
buf1.copy(obj);
s = obj->getString();
- decrypt = new Decrypt(fileKey, objNum, objGen);
+ decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
for (i = 0, p = obj->getString()->getCString();
i < s->getLength();
++i, ++p) {
diff --git a/pdftops/Parser.h b/pdftops/Parser.h
index 6e6184499e..463d99827d 100644
--- a/pdftops/Parser.h
+++ b/pdftops/Parser.h
@@ -23,7 +23,7 @@ class Parser {
public:
// Constructor.
- Parser(Lexer *lexer1);
+ Parser(XRef *xrefA, Lexer *lexerA);
// Destructor.
~Parser();
@@ -31,7 +31,8 @@ public:
// Get the next object from the input stream.
#ifndef NO_DECRYPTION
Object *getObj(Object *obj,
- Guchar *fileKey = NULL, int objNum = 0, int objGen = 0);
+ Guchar *fileKey = NULL, int keyLength = 0,
+ int objNum = 0, int objGen = 0);
#else
Object *getObj(Object *obj);
#endif
@@ -44,6 +45,7 @@ public:
private:
+ XRef *xref; // the xref table for this PDF file
Lexer *lexer; // input stream
Object buf1, buf2; // next two tokens
int inlineImg; // set when inline image data is encountered
diff --git a/pdftops/README b/pdftops/README
index f6bc9ebee0..4835a82f82 100644
--- a/pdftops/README
+++ b/pdftops/README
@@ -1,11 +1,11 @@
-xpdf
+Xpdf
====
-version 0.90
-99-aug-02
+version 0.93
+2001-oct-25
-The xpdf software and documentation are
-copyright 1996-1999 Derek B. Noonburg.
+The Xpdf software and documentation are
+copyright 1996-2001 Derek B. Noonburg.
Email: derekn@foolabs.com
WWW: http://www.foolabs.com/xpdf/
@@ -14,7 +14,7 @@ The PDF data structures, operators, and specification are
copyright 1995 Adobe Systems Inc.
-What is xpdf?
+What is Xpdf?
-------------
Xpdf is a viewer for Portable Document Format (PDF) files. (These are
@@ -24,8 +24,8 @@ OS/2. The non-X components of the package (pdftops, pdftotext, etc.)
also run on Win32 systems and should run on pretty much any system
with a decent C++ compiler.
-Xpdf is designed to be small and efficient. It does not use the Motif
-or Xt libraries. It can use standard X fonts.
+Xpdf is designed to be small and efficient. It can use Type 1,
+TrueType, or standard X fonts.
Distribution
@@ -39,16 +39,16 @@ confusing, the basic idea is good.
In order to cut down on the confusion a little bit, here are some
informal clarifications:
-- I don't mind if you redistribute xpdf in source and/or binary form,
+- I don't mind if you redistribute Xpdf in source and/or binary form,
as long as you include all of the documentation: README, man pages
(or help files), and COPYING. (Note that the README file contains a
pointer to a web page with the source code.)
-- Selling a CD-ROM that contains xpdf is fine with me, as long as it
+- Selling a CD-ROM that contains Xpdf is fine with me, as long as it
includes the documentation. I wouldn't mind receiving a sample
copy, but it's not necessary.
-- If you make useful changes to xpdf, please make the source code
+- If you make useful changes to Xpdf, please make the source code
available -- post it on a web site, email it to me, whatever.
If you're interested in commercial licensing, please contact me by
@@ -58,7 +58,7 @@ email: derekn@foolabs.com .
Compatibility
-------------
-Xpdf is developed and tested on a Linux 2.0 x86 system.
+Xpdf is developed and tested on a Linux 2.2 x86 system.
In addition, it has been compiled by others on Solaris, AIX, HP-UX,
SCO UnixWare, Digital Unix, Irix, and numerous other Unix
@@ -66,24 +66,24 @@ implementations, as well as VMS and OS/2. It should work on pretty
much any system which runs X11 and has Unix-like libraries. You'll
need ANSI C++ and C compilers to compile it.
-The non-X components of xpdf (pdftops, pdftotext, pdfinfo, pdfimages)
-can also be compiled on Win32 systems. See the xpdf web page for
+The non-X components of Xpdf (pdftops, pdftotext, pdfinfo, pdfimages)
+can also be compiled on Win32 systems. See the Xpdf web page for
details.
-If you compiled xpdf for a system not listed on the web page, please
+If you compile Xpdf for a system not listed on the web page, please
let me know. If you're willing to make your binary available by ftp
-or on the web, I'll be happy to add a link from the xpdf web page. I
+or on the web, I'll be happy to add a link from the Xpdf web page. I
have decided not to host any binaries I didn't compile myself (for
disk space and support reasons).
-If you can't get xpdf to compile on your system, send me email and
+If you can't get Xpdf to compile on your system, send me email and
I'll try to help.
-Xpdf has been ported to the Acorn, Amiga, and BeOS. See the xpdf web
-page for links.
+Xpdf has been ported to the Acorn, Amiga, BeOS, and EPOC. See the
+Xpdf web page for links.
-Getting xpdf
+Getting Xpdf
------------
The latest version is available from:
@@ -102,7 +102,7 @@ list of people. If you'd like to receive email notification of new
versions, just let me know.
-Running xpdf
+Running Xpdf
------------
To run xpdf, simply type:
@@ -168,7 +168,22 @@ For Japanese support, you will need a Japanese font of the form:
-*-fixed-medium-r-normal-*-NN-*-*-*-*-*-jisx0208.1983-0
-and an X server that can handle 16-bit fonts.
+and an X server that can handle 16-bit fonts. You can also set this
+font using the xpdf.japaneseFont resource.
+
+For Chinese GB (simplified Chinese) support, you will need a font of
+the form:
+
+ -*-fangsong ti-medium-r-normal-*-%s-*-*-*-*-*-gb2312.1980-0
+
+You can replace this font using the xpdf.chineseGBFont resource.
+
+For Chinese CNS (traditional Chinese) support, you will need a font of
+the form:
+
+ -*-fixed-medium-r-normal--*-%s-*-*-*-*-big5-0
+
+You can replace this font using the xpdf.chineseCNSFont resource.
If compiled with t1lib support, xpdf will use t1lib to render embedded
Type 1 and Type 1C fonts. In addition, xpdf can be configured to use
@@ -191,6 +206,28 @@ example:
xpdf.t1Symbol: /usr/local/fonts/Symbol.pfa
xpdf.t1ZapfDingbats: /usr/local/fonts/ZapfDingbats.pfa
+Ghostscript comes with a set of free, high-quality Type 1 fonts,
+donated by URW++ Design and Development Incorporated. The xpdf X
+resources needed for these fonts are:
+
+ xpdf.t1TimesRoman: /usr/ghostscript/fonts/n021003l.pfb
+ xpdf.t1TimesItalic: /usr/ghostscript/fonts/n021023l.pfb
+ xpdf.t1TimesBold: /usr/ghostscript/fonts/n021004l.pfb
+ xpdf.t1TimesBoldItalic: /usr/ghostscript/fonts/n021024l.pfb
+ xpdf.t1Helvetica: /usr/ghostscript/fonts/n019003l.pfb
+ xpdf.t1HelveticaOblique: /usr/ghostscript/fonts/n019023l.pfb
+ xpdf.t1HelveticaBold: /usr/ghostscript/fonts/n019004l.pfb
+ xpdf.t1HelveticaBoldOblique: /usr/ghostscript/fonts/n019024l.pfb
+ xpdf.t1Courier: /usr/ghostscript/fonts/n022003l.pfb
+ xpdf.t1CourierOblique: /usr/ghostscript/fonts/n022023l.pfb
+ xpdf.t1CourierBold: /usr/ghostscript/fonts/n022004l.pfb
+ xpdf.t1CourierBoldOblique: /usr/ghostscript/fonts/n022024l.pfb
+ xpdf.t1Symbol: /usr/ghostscript/fonts/s050000l.pfb
+ xpdf.t1ZapfDingbats: /usr/ghostscript/fonts/d050000l.pfb
+
+You will obviously need to replace '/usr/ghostscript/fonts' with the
+appropriate path on your system.
+
The Unisys LZW Patent
---------------------
@@ -198,13 +235,13 @@ The Unisys LZW Patent
Nearly all PDF files include data which has been compressed with the
LZW compression algorithm. Unfortunately, LZW is covered by a
software patent which is owned by Unisys Corporation. Unisys refuses
-to license this patent for PDF-related use in software such as xpdf
+to license this patent for PDF-related use in software such as Xpdf
which is released for free and which may be freely redistributed.
(This is same algorithm which is used by GIF. However, Unisys is not
doing licensing for free PDF viwers in the same way as for free GIF
viewers.)
-As a workaround, xpdf converts PDF-format LZW data to compress-format
+As a workaround, Xpdf converts PDF-format LZW data to compress-format
LZW data. (The standard UNIX compress utility also uses LZW, but with
a slightly different file format.) This conversion does *not*
decompress the data; it simply converts it to a different file format.
@@ -221,7 +258,7 @@ For Unisys's slant on things (mostly regarding GIF), see
an email address for feedback.
-Compiling xpdf
+Compiling Xpdf
--------------
See the separate file, INSTALL.
@@ -230,10 +267,9 @@ See the separate file, INSTALL.
Bugs
----
-This release of xpdf should improve the situation with embedded
-fonts. However, Type 3 and TrueType fonts are still not handled.
+Type 3 fonts are still not well supported by Xpdf.
-If you find a bug in xpdf, i.e., if it prints an error message,
+If you find a bug in Xpdf, i.e., if it prints an error message,
crashes, or incorrectly displays a document, and you don't see that
bug listed here, please send me email, with a pointer (URL, ftp site,
etc.) to the PDF file.
@@ -245,7 +281,8 @@ Acknowledgments
Thanks to:
* Patrick Voigt for help with the remote server code.
-* Patrick Moreau and Martin P.J. Zinser for the VMS port.
+* Patrick Moreau, Martin P.J. Zinser, and David Mathog for the VMS
+ port.
* David Boldt and Rick Rodgers for sample man pages.
* Brendan Miller for the icon idea.
* Olly Betts for help testing pdftotext.
@@ -255,40 +292,73 @@ Thanks to:
* Leo Smiers for the decryption patches.
* Rainer Menzner for creating t1lib, and for helping me adapt it to
xpdf.
+* Pine Tree Systems A/S for funding the OPI and EPS support in
+ pdftops.
+* Easy Software Products for funding the "sh" operator support.
References
----------
-Adobe Systems Inc., _Portable Document Format Reference Manual_.
-Addison-Wesley, 1993, ISBN 0-201-62628-4.
-[The printed manual for PDF version 1.0.]
+Adobe Systems Inc., _PDF Reference_, 2nd ed.
+Addison-Wesley, 2000, ISBN 0-201-61588-6.
+[The printed manual for PDF version 1.3.]
-Adobe Systems Inc., _Portable Document Format Reference Manual_,
-Version 1.3. March 11, 1999.
-http://partners.adobe.com/asn/developer/PDFS/TN/PDFSPEC.PDF
-[Updated manual for PDF 1.3.]
+Adobe Systems Inc., _Portable Document Format: Changes from Version
+1.3 to 1.4_, Adobe Developer Support Technical Note #5409.
+June 11, 2001.
+http://partners.adobe.com/asn/developer/acrosdk/docs/filefmtspecs/PDF14Deltas.pdf
+[Updates for PDF 1.4.]
-Adobe Systems Inc., _PostScript Language Reference Manual_, 2nd ed.
-Addison-Wesley, 1990, ISBN 0-201-18127-4.
+Adobe Systems Inc., _PostScript Language Reference_, 3rd ed.
+Addison-Wesley, 1999, ISBN 0-201-37922-8.
[The official PostScript manual.]
+Adobe Systems, Inc., _The Type 42 Font Format Specification_,
+Adobe Developer Support Technical Specification #5012. 1998.
+http://partners.adobe.com/asn/developer/pdfs/tn/5012.Type42_Spec.pdf
+[Type 42 is the format used to embed TrueType fonts in PostScript
+files.]
+
Adobe Systems, Inc., _Adobe CMap and CIDFont Files Specification_,
Adobe Developer Support Technical Specification #5014. 1995.
http://www.adobe.com/supportservice/devrelations/PDFS/TN/5014.CIDFont_Spec.pdf
-[CMap file format needed for Japanese font support.]
+[CMap file format needed for Japanese and Chinese font support.]
Adobe Systems, Inc., _Adobe-Japan1-2 Character Collection for
-CID-Keyed Fonts_ (Bitmap Character Image Version), Adobe Developer
-Support Technical Note #5078-b. 1994.
-http://www.adobe.com/supportservice/devrelations/PDFS/TN/5078b.pdf
-[The complete Adobe Japanese character set.]
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5078.
+1994.
+http://partners.adobe.com/asn/developer/PDFS/TN/5078.CID_Glyph.pdf
+[The Adobe Japanese character set.]
+
+Adobe Systems, Inc., _Adobe-GB1-3 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5079.
+1998.
+http://partners.adobe.com/asn/developer/PDFS/TN/5079.GB_CharColl.pdf
+[The Adobe Chinese GB character set.]
+
+Adobe Systems, Inc., _Adobe-CNS1-3 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5080.
+2000.
+http://partners.adobe.com/asn/developer/PDFS/TN/5080.CNS_CharColl.pdf
+[The Adobe Chinese CNS character set.]
Adobe Systems Inc., _Supporting the DCT Filters in PostScript Level
2_, Adobe Developer Support Technical Note #5116. 1992.
http://www.adobe.com/supportservice/devrelations/PDFS/TN/5116.PS2_DCT.PDF
[Description of the DCTDecode filter parameters.]
+Adobe Systems Inc., _Open Prepress Interface (OPI) Specification -
+Version 2.0_, Adobe Developer Support Technical Note #5660. 2000.
+http://partners.adobe.com/asn/developer/PDFS/TN/5660.OPI_2.0.pdf
+
+Adobe Systems Inc., CMap files.
+ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/
+[The actual CMap files for the 16-bit CJK encodings.]
+
+Aldus Corp., _OPI: Open Prepress Interface Specification 1.3_. 1993.
+http://partners.adobe.com/asn/developer/PDFS/TN/OPI_13.pdf
+
Anonymous, RC4 source code.
ftp://ftp.ox.ac.uk/pub/crypto/misc/rc4.tar.gz
ftp://idea.sec.dsi.unimi.it/pub/crypt/code/rc4.tar.gz
@@ -329,6 +399,14 @@ Fast 1-D DCT Algorithms with 11 Multiplications". IEEE Intl. Conf. on
Acoustics, Speech & Signal Processing, 1989, 988-991.
[The fast IDCT algorithm used in the DCTDecode filter.]
+Microsoft, _TrueType 1.0 Font Files_, rev. 1.66. 1995.
+http://www.microsoft.com/typography/tt/tt.htm
+[The TrueType font spec (in MS Word format, naturally).]
+
+Charles Poynton, "Color FAQ".
+http://www.inforamp.net/~poynton/ColorFAQ.html
+[The mapping from the CIE 1931 (XYZ) color space to RGB.]
+
R. Rivest, "The MD5 Message-Digest Algorithm". RFC 1321.
[MD5 is used in PDF document encryption.]
diff --git a/pdftops/SFont.h b/pdftops/SFont.h
index 4758664fa1..cab17961e2 100644
--- a/pdftops/SFont.h
+++ b/pdftops/SFont.h
@@ -22,8 +22,8 @@
class SFontEngine {
public:
- SFontEngine(Display *display, Visual *visual, int depth,
- Colormap colormap);
+ SFontEngine(Display *displayA, Visual *visualA, int depthA,
+ Colormap colormapA);
virtual ~SFontEngine();
// Use a TrueColor visual. Pixel values are computed as:
@@ -32,8 +32,8 @@ public:
//
// where r, g, and b are scaled to the ranges [0,rMax], [0,gMax],
// and [0,bMax], respectively.
- virtual void useTrueColor(int rMax, int rShift, int gMax, int gShift,
- int bMax, int bShift);
+ virtual void useTrueColor(int rMaxA, int rShiftA, int gMaxA, int gShiftA,
+ int bMaxA, int bShiftA);
// Use an RGB color cube. is an array containing
// ** pixel values in red,green,blue order, e.g.,
@@ -53,7 +53,7 @@ public:
//
// The array is not copied and must remain valid for the
// lifetime of this SFont object.
- virtual void useColorCube(Gulong *colors, int nRGB);
+ virtual void useColorCube(Gulong *colorsA, int nRGBA);
protected:
diff --git a/pdftops/StdFontInfo.h b/pdftops/StdFontInfo.h
index 4b3e43539a..0db033f6bd 100644
--- a/pdftops/StdFontInfo.h
+++ b/pdftops/StdFontInfo.h
@@ -16,7 +16,7 @@
//------------------------------------------------------------------------
#define type1StdEncodingSize 256
-static const char *type1StdEncodingNames[type1StdEncodingSize] = {
+static char *type1StdEncodingNames[type1StdEncodingSize] = {
NULL,
NULL,
NULL,
@@ -282,7 +282,7 @@ static FontEncoding type1StdEncoding(type1StdEncodingNames,
//------------------------------------------------------------------------
#define type1ExpertEncodingSize 256
-static const char *type1ExpertEncodingNames[type1ExpertEncodingSize] = {
+static char *type1ExpertEncodingNames[type1ExpertEncodingSize] = {
NULL,
NULL,
NULL,
diff --git a/pdftops/Stream.cxx b/pdftops/Stream.cxx
index 5677dff9d9..a8a88e623d 100644
--- a/pdftops/Stream.cxx
+++ b/pdftops/Stream.cxx
@@ -88,9 +88,7 @@ char *Stream::getLine(char *buf, int size) {
return buf;
}
-GString *Stream::getPSFilter(const char *indent) {
- (void)indent;
-
+GString *Stream::getPSFilter(char *indent) {
return new GString();
}
@@ -138,7 +136,7 @@ Stream *Stream::addFilters(Object *dict) {
return str;
}
-Stream *Stream::makeFilter(const char *name, Stream *str, Object *params) {
+Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
int pred; // parameters
int colors;
int bits;
@@ -267,8 +265,8 @@ Stream *Stream::makeFilter(const char *name, Stream *str, Object *params) {
// BaseStream
//------------------------------------------------------------------------
-BaseStream::BaseStream(Object *ndict) {
- dict = *ndict;
+BaseStream::BaseStream(Object *dictA) {
+ dict = *dictA;
#ifndef NO_DECRYPTION
decrypt = NULL;
#endif
@@ -283,8 +281,9 @@ BaseStream::~BaseStream() {
}
#ifndef NO_DECRYPTION
-void BaseStream::doDecryption(Guchar *fileKey, int objNum, int objGen) {
- decrypt = new Decrypt(fileKey, objNum, objGen);
+void BaseStream::doDecryption(Guchar *fileKey, int keyLength,
+ int objNum, int objGen) {
+ decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
}
#endif
@@ -292,8 +291,8 @@ void BaseStream::doDecryption(Guchar *fileKey, int objNum, int objGen) {
// FilterStream
//------------------------------------------------------------------------
-FilterStream::FilterStream(Stream *nstr) {
- str = nstr;
+FilterStream::FilterStream(Stream *strA) {
+ str = strA;
}
FilterStream::~FilterStream() {
@@ -304,8 +303,6 @@ void FilterStream::close() {
}
void FilterStream::setPos(int pos) {
- (void)pos;
-
error(-1, "Internal: called setPos() on FilterStream");
}
@@ -313,13 +310,13 @@ void FilterStream::setPos(int pos) {
// ImageStream
//------------------------------------------------------------------------
-ImageStream::ImageStream(Stream *nstr, int nwidth, int nnComps, int nnBits) {
+ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) {
int imgLineSize;
- str = nstr;
- width = nwidth;
- nComps = nnComps;
- nBits = nnBits;
+ str = strA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
nVals = width * nComps;
if (nBits == 1) {
@@ -400,13 +397,13 @@ void ImageStream::skipLine() {
// StreamPredictor
//------------------------------------------------------------------------
-StreamPredictor::StreamPredictor(Stream *nstr, int npredictor,
- int nwidth, int nnComps, int nnBits) {
- str = nstr;
- predictor = npredictor;
- width = nwidth;
- nComps = nnComps;
- nBits = nnBits;
+StreamPredictor::StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA) {
+ str = strA;
+ predictor = predictorA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
nVals = width * nComps;
pixBytes = (nComps * nBits + 7) >> 3;
@@ -556,11 +553,11 @@ GBool StreamPredictor::getNextLine() {
// FileStream
//------------------------------------------------------------------------
-FileStream::FileStream(FILE *nf, int nstart, int nlength, Object *dict):
- BaseStream(dict) {
- f = nf;
- start = nstart;
- length = nlength;
+FileStream::FileStream(FILE *fA, int startA, int lengthA, Object *dictA):
+ BaseStream(dictA) {
+ f = fA;
+ start = startA;
+ length = lengthA;
bufPtr = bufEnd = buf;
bufPos = start;
savePos = -1;
@@ -570,8 +567,8 @@ FileStream::~FileStream() {
close();
}
-Stream *FileStream::makeSubStream(int nstart, int nlength, Object *ndict) {
- return new FileStream(f, nstart, nlength, ndict);
+Stream *FileStream::makeSubStream(int startA, int lengthA, Object *dictA) {
+ return new FileStream(f, startA, lengthA, dictA);
}
void FileStream::reset() {
@@ -623,25 +620,29 @@ GBool FileStream::fillBuf() {
return gTrue;
}
-void FileStream::setPos(int pos1) {
+void FileStream::setPos(int pos) {
long size;
- if (pos1 >= 0) {
- fseek(f, pos1, SEEK_SET);
- bufPos = pos1;
+ if (pos >= 0) {
+ fseek(f, pos, SEEK_SET);
+ bufPos = pos;
} else {
fseek(f, 0, SEEK_END);
size = ftell(f);
- if (pos1 < -size)
- pos1 = (int)(-size);
- fseek(f, pos1, SEEK_END);
+ if (pos < -size)
+ pos = (int)(-size);
+#ifdef __CYGWIN32__
+ //~ work around a bug in cygwin's implementation of fseek
+ rewind(f);
+#endif
+ fseek(f, pos, SEEK_END);
bufPos = (int)ftell(f);
}
bufPtr = bufEnd = buf;
}
void FileStream::moveStart(int delta) {
- this->start += delta;
+ start += delta;
bufPtr = bufEnd = buf;
bufPos = start;
}
@@ -650,26 +651,20 @@ void FileStream::moveStart(int delta) {
// EmbedStream
//------------------------------------------------------------------------
-EmbedStream::EmbedStream(Stream *nstr, Object *ndict):
- BaseStream(ndict) {
- str = nstr;
+EmbedStream::EmbedStream(Stream *strA, Object *dictA):
+ BaseStream(dictA) {
+ str = strA;
}
EmbedStream::~EmbedStream() {
}
-Stream *EmbedStream::makeSubStream(int start, int length, Object *ndict) {
- (void)start;
- (void)length;
- (void)ndict;
-
+Stream *EmbedStream::makeSubStream(int start, int length, Object *dictA) {
error(-1, "Internal: called makeSubStream() on EmbedStream");
return NULL;
}
void EmbedStream::setPos(int pos) {
- (void)pos;
-
error(-1, "Internal: called setPos() on EmbedStream");
}
@@ -679,8 +674,6 @@ int EmbedStream::getStart() {
}
void EmbedStream::moveStart(int start) {
- (void)start;
-
error(-1, "Internal: called moveStart() on EmbedStream");
}
@@ -688,8 +681,8 @@ void EmbedStream::moveStart(int start) {
// ASCIIHexStream
//------------------------------------------------------------------------
-ASCIIHexStream::ASCIIHexStream(Stream *str):
- FilterStream(str) {
+ASCIIHexStream::ASCIIHexStream(Stream *strA):
+ FilterStream(strA) {
buf = EOF;
eof = gFalse;
}
@@ -757,17 +750,17 @@ int ASCIIHexStream::lookChar() {
return buf;
}
-GString *ASCIIHexStream::getPSFilter(const char *indent) {
+GString *ASCIIHexStream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/ASCIIHexDecode filter\n");
return s;
}
GBool ASCIIHexStream::isBinary(GBool last) {
- (void)last;
-
return str->isBinary(gFalse);
}
@@ -775,8 +768,8 @@ GBool ASCIIHexStream::isBinary(GBool last) {
// ASCII85Stream
//------------------------------------------------------------------------
-ASCII85Stream::ASCII85Stream(Stream *str):
- FilterStream(str) {
+ASCII85Stream::ASCII85Stream(Stream *strA):
+ FilterStream(strA) {
index = n = 0;
eof = gFalse;
}
@@ -835,17 +828,17 @@ int ASCII85Stream::lookChar() {
return b[index];
}
-GString *ASCII85Stream::getPSFilter(const char *indent) {
+GString *ASCII85Stream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/ASCII85Decode filter\n");
return s;
}
GBool ASCII85Stream::isBinary(GBool last) {
- (void)last;
-
return str->isBinary(gFalse);
}
@@ -853,15 +846,15 @@ GBool ASCII85Stream::isBinary(GBool last) {
// LZWStream
//------------------------------------------------------------------------
-LZWStream::LZWStream(Stream *str, int predictor1, int columns1, int colors1,
- int bits1, int early1):
- FilterStream(str) {
- if (predictor1 != 1) {
- pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1);
+LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
} else {
pred = NULL;
}
- early = early1;
+ early = earlyA;
zPipe = NULL;
bufPtr = bufEnd = buf;
}
@@ -1149,20 +1142,20 @@ GBool LZWStream::fillBuf() {
return n > 0;
}
-GString *LZWStream::getPSFilter(const char *indent) {
+GString *LZWStream::getPSFilter(char *indent) {
GString *s;
if (pred) {
return NULL;
}
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/LZWDecode filter\n");
return s;
}
GBool LZWStream::isBinary(GBool last) {
- (void)last;
-
return str->isBinary(gTrue);
}
@@ -1170,8 +1163,8 @@ GBool LZWStream::isBinary(GBool last) {
// RunLengthStream
//------------------------------------------------------------------------
-RunLengthStream::RunLengthStream(Stream *str):
- FilterStream(str) {
+RunLengthStream::RunLengthStream(Stream *strA):
+ FilterStream(strA) {
bufPtr = bufEnd = buf;
eof = gFalse;
}
@@ -1186,17 +1179,17 @@ void RunLengthStream::reset() {
eof = gFalse;
}
-GString *RunLengthStream::getPSFilter(const char *indent) {
+GString *RunLengthStream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("/RunLengthDecode filter\n");
return s;
}
GBool RunLengthStream::isBinary(GBool last) {
- (void)last;
-
return str->isBinary(gTrue);
}
@@ -1230,17 +1223,17 @@ GBool RunLengthStream::fillBuf() {
// CCITTFaxStream
//------------------------------------------------------------------------
-CCITTFaxStream::CCITTFaxStream(Stream *str, int nencoding, GBool nendOfLine,
- GBool nbyteAlign, int ncolumns, int nrows,
- GBool nendOfBlock, GBool nblack):
- FilterStream(str) {
- encoding = nencoding;
- endOfLine = nendOfLine;
- byteAlign = nbyteAlign;
- columns = ncolumns;
- rows = nrows;
- endOfBlock = nendOfBlock;
- black = nblack;
+CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA):
+ FilterStream(strA) {
+ encoding = encodingA;
+ endOfLine = endOfLineA;
+ byteAlign = byteAlignA;
+ columns = columnsA;
+ rows = rowsA;
+ endOfBlock = endOfBlockA;
+ black = blackA;
refLine = (short *)gmalloc((columns + 3) * sizeof(short));
codingLine = (short *)gmalloc((columns + 2) * sizeof(short));
@@ -1736,11 +1729,13 @@ short CCITTFaxStream::lookBits(int n) {
return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n));
}
-GString *CCITTFaxStream::getPSFilter(const char *indent) {
+GString *CCITTFaxStream::getPSFilter(char *indent) {
GString *s;
char s1[50];
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("<< ");
if (encoding != 0) {
sprintf(s1, "/K %d ", encoding);
@@ -1769,8 +1764,6 @@ GString *CCITTFaxStream::getPSFilter(const char *indent) {
}
GBool CCITTFaxStream::isBinary(GBool last) {
- (void)last;
-
return str->isBinary(gTrue);
}
@@ -1832,8 +1825,8 @@ static int dctZigZag[64] = {
63
};
-DCTStream::DCTStream(Stream *str):
- FilterStream(str) {
+DCTStream::DCTStream(Stream *strA):
+ FilterStream(strA) {
int i, j;
width = height = 0;
@@ -2729,17 +2722,17 @@ int DCTStream::read16() {
return (c1 << 8) + c2;
}
-GString *DCTStream::getPSFilter(const char *indent) {
+GString *DCTStream::getPSFilter(char *indent) {
GString *s;
- s = str->getPSFilter(indent);
+ if (!(s = str->getPSFilter(indent))) {
+ return NULL;
+ }
s->append(indent)->append("<< >> /DCTDecode filter\n");
return s;
}
GBool DCTStream::isBinary(GBool last) {
- (void)last;
-
return str->isBinary(gTrue);
}
@@ -2816,11 +2809,11 @@ FlateDecode FlateStream::distDecode[flateMaxDistCodes] = {
{13, 24577}
};
-FlateStream::FlateStream(Stream *str, int predictor1, int columns1,
- int colors1, int bits1):
- FilterStream(str) {
- if (predictor1 != 1) {
- pred = new StreamPredictor(this, predictor1, columns1, colors1, bits1);
+FlateStream::FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
} else {
pred = NULL;
}
@@ -2915,15 +2908,11 @@ int FlateStream::getRawChar() {
return c;
}
-GString *FlateStream::getPSFilter(const char *indent) {
- (void)indent;
-
+GString *FlateStream::getPSFilter(char *indent) {
return NULL;
}
GBool FlateStream::isBinary(GBool last) {
- (void)last;
-
return str->isBinary(gTrue);
}
@@ -3252,8 +3241,8 @@ int FlateStream::getCodeWord(int bits) {
// EOFStream
//------------------------------------------------------------------------
-EOFStream::EOFStream(Stream *str):
- FilterStream(str) {
+EOFStream::EOFStream(Stream *strA):
+ FilterStream(strA) {
}
EOFStream::~EOFStream() {
@@ -3264,9 +3253,9 @@ EOFStream::~EOFStream() {
// FixedLengthEncoder
//------------------------------------------------------------------------
-FixedLengthEncoder::FixedLengthEncoder(Stream *str, int length1):
- FilterStream(str) {
- length = length1;
+FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA):
+ FilterStream(strA) {
+ length = lengthA;
count = 0;
}
@@ -3300,8 +3289,8 @@ int FixedLengthEncoder::lookChar() {
// ASCII85Encoder
//------------------------------------------------------------------------
-ASCII85Encoder::ASCII85Encoder(Stream *str):
- FilterStream(str) {
+ASCII85Encoder::ASCII85Encoder(Stream *strA):
+ FilterStream(strA) {
bufPtr = bufEnd = buf;
lineLen = 0;
eof = gFalse;
@@ -3372,8 +3361,8 @@ GBool ASCII85Encoder::fillBuf() {
// RunLengthEncoder
//------------------------------------------------------------------------
-RunLengthEncoder::RunLengthEncoder(Stream *str):
- FilterStream(str) {
+RunLengthEncoder::RunLengthEncoder(Stream *strA):
+ FilterStream(strA) {
bufPtr = bufEnd = nextEnd = buf;
eof = gFalse;
}
@@ -3434,7 +3423,6 @@ GBool RunLengthEncoder::fillBuf() {
c = 0; // make gcc happy
if (c1 == c2) {
n = 2;
- c = 0; // suppress bogus compiler warning
while (n < 128 && (c = str->getChar()) == c1)
++n;
buf[0] = (char)(257 - n);
diff --git a/pdftops/Stream.h b/pdftops/Stream.h
index f77bade503..1f9c561d19 100644
--- a/pdftops/Stream.h
+++ b/pdftops/Stream.h
@@ -79,10 +79,10 @@ public:
virtual int getPos() = 0;
// Go to a position in the stream.
- virtual void setPos(int pos1) = 0;
+ virtual void setPos(int pos) = 0;
// Get PostScript command for the filter(s).
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
// Does this stream type potentially contain non-printable chars?
virtual GBool isBinary(GBool last = gTrue) = 0;
@@ -102,7 +102,7 @@ public:
private:
- Stream *makeFilter(const char *name, Stream *str, Object *params);
+ Stream *makeFilter(char *name, Stream *str, Object *params);
int ref; // reference count
};
@@ -116,10 +116,10 @@ private:
class BaseStream: public Stream {
public:
- BaseStream(Object *dict);
+ BaseStream(Object *dictA);
virtual ~BaseStream();
virtual Stream *makeSubStream(int start, int length, Object *dict) = 0;
- virtual void setPos(int pos1) = 0;
+ virtual void setPos(int pos) = 0;
virtual BaseStream *getBaseStream() { return this; }
virtual Dict *getDict() { return dict.getDict(); }
@@ -129,7 +129,7 @@ public:
#ifndef NO_DECRYPTION
// Set decryption for this stream.
- void doDecryption(Guchar *fileKey, int objNum, int objGen);
+ void doDecryption(Guchar *fileKey, int keyLength, int objNum, int objGen);
#endif
#ifndef NO_DECRYPTION
@@ -152,7 +152,7 @@ private:
class FilterStream: public Stream {
public:
- FilterStream(Stream *str);
+ FilterStream(Stream *strA);
virtual ~FilterStream();
virtual void close();
virtual int getPos() { return str->getPos(); }
@@ -175,7 +175,7 @@ public:
// Create an image stream object for an image with the specified
// parameters. Note that these are the actual image parameters,
// which may be different from the predictor parameters.
- ImageStream(Stream *str, int width, int nComps, int nBits);
+ ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA);
~ImageStream();
@@ -209,8 +209,8 @@ public:
// Create a predictor object. Note that the parameters are for the
// predictor, and may not match the actual image parameters.
- StreamPredictor(Stream *str, int predictor,
- int width, int nComps, int nBits);
+ StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA);
~StreamPredictor();
@@ -242,9 +242,9 @@ private:
class FileStream: public BaseStream {
public:
- FileStream(FILE *f, int start, int length, Object *dict);
+ FileStream(FILE *fA, int startA, int lengthA, Object *dictA);
virtual ~FileStream();
- virtual Stream *makeSubStream(int start, int length, Object *dict);
+ virtual Stream *makeSubStream(int startA, int lengthA, Object *dictA);
virtual StreamKind getKind() { return strFile; }
virtual void reset();
virtual void close();
@@ -253,7 +253,7 @@ public:
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
virtual int getPos() { return bufPos + (bufPtr - buf); }
- virtual void setPos(int pos1);
+ virtual void setPos(int pos);
virtual GBool isBinary(GBool last = gTrue) { return last; }
virtual int getStart() { return start; }
virtual void moveStart(int delta);
@@ -285,9 +285,9 @@ private:
class EmbedStream: public BaseStream {
public:
- EmbedStream(Stream *str, Object *dict);
+ EmbedStream(Stream *strA, Object *dictA);
virtual ~EmbedStream();
- virtual Stream *makeSubStream(int start, int length, Object *dict);
+ virtual Stream *makeSubStream(int start, int length, Object *dictA);
virtual StreamKind getKind() { return str->getKind(); }
virtual void reset() {}
virtual int getChar() { return str->getChar(); }
@@ -310,14 +310,14 @@ private:
class ASCIIHexStream: public FilterStream {
public:
- ASCIIHexStream(Stream *str);
+ ASCIIHexStream(Stream *strA);
virtual ~ASCIIHexStream();
virtual StreamKind getKind() { return strASCIIHex; }
virtual void reset();
virtual int getChar()
{ int c = lookChar(); buf = EOF; return c; }
virtual int lookChar();
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -333,14 +333,14 @@ private:
class ASCII85Stream: public FilterStream {
public:
- ASCII85Stream(Stream *str);
+ ASCII85Stream(Stream *strA);
virtual ~ASCII85Stream();
virtual StreamKind getKind() { return strASCII85; }
virtual void reset();
virtual int getChar()
{ int ch = lookChar(); ++index; return ch; }
virtual int lookChar();
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -358,15 +358,15 @@ private:
class LZWStream: public FilterStream {
public:
- LZWStream(Stream *str, int predictor1, int columns1, int colors1,
- int bits1, int early1);
+ LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA);
virtual ~LZWStream();
virtual StreamKind getKind() { return strLZW; }
virtual void reset();
virtual int getChar();
virtual int lookChar();
virtual int getRawChar();
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -394,7 +394,7 @@ private:
class RunLengthStream: public FilterStream {
public:
- RunLengthStream(Stream *str);
+ RunLengthStream(Stream *strA);
virtual ~RunLengthStream();
virtual StreamKind getKind() { return strRunLength; }
virtual void reset();
@@ -402,7 +402,7 @@ public:
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -424,16 +424,16 @@ struct CCITTCodeTable;
class CCITTFaxStream: public FilterStream {
public:
- CCITTFaxStream(Stream *str, int encoding, GBool endOfLine,
- GBool byteAlign, int columns, int rows,
- GBool endOfBlock, GBool black);
+ CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA);
virtual ~CCITTFaxStream();
virtual StreamKind getKind() { return strCCITTFax; }
virtual void reset();
virtual int getChar()
{ int c = lookChar(); buf = EOF; return c; }
virtual int lookChar();
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -489,13 +489,13 @@ struct DCTHuffTable {
class DCTStream: public FilterStream {
public:
- DCTStream(Stream *str);
+ DCTStream(Stream *strA);
virtual ~DCTStream();
virtual StreamKind getKind() { return strDCT; }
virtual void reset();
virtual int getChar();
virtual int lookChar();
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
virtual GBool isBinary(GBool last = gTrue);
Stream *getRawStream() { return str; }
@@ -573,15 +573,15 @@ struct FlateDecode {
class FlateStream: public FilterStream {
public:
- FlateStream(Stream *str, int predictor1, int columns1,
- int colors1, int bits1);
+ FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits);
virtual ~FlateStream();
virtual StreamKind getKind() { return strFlate; }
virtual void reset();
virtual int getChar();
virtual int lookChar();
virtual int getRawChar();
- virtual GString *getPSFilter(const char *indent);
+ virtual GString *getPSFilter(char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -624,14 +624,14 @@ private:
class EOFStream: public FilterStream {
public:
- EOFStream(Stream *str);
+ EOFStream(Stream *strA);
virtual ~EOFStream();
virtual StreamKind getKind() { return strWeird; }
virtual void reset() {}
virtual int getChar() { return EOF; }
virtual int lookChar() { return EOF; }
- virtual GString *getPSFilter(const char *indent) { (void)indent; return NULL; }
- virtual GBool isBinary(GBool last = gTrue) { (void)last; return gFalse; }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
};
//------------------------------------------------------------------------
@@ -641,15 +641,15 @@ public:
class FixedLengthEncoder: public FilterStream {
public:
- FixedLengthEncoder(Stream *str, int length1);
+ FixedLengthEncoder(Stream *strA, int lengthA);
~FixedLengthEncoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
virtual void close();
virtual int getChar();
virtual int lookChar();
- virtual GString *getPSFilter(const char *indent) { (void)indent; return NULL; }
- virtual GBool isBinary(GBool last = gTrue) { (void)last; return gFalse; }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
virtual GBool isEncoder() { return gTrue; }
private:
@@ -665,7 +665,7 @@ private:
class ASCII85Encoder: public FilterStream {
public:
- ASCII85Encoder(Stream *str);
+ ASCII85Encoder(Stream *strA);
virtual ~ASCII85Encoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
@@ -674,8 +674,8 @@ public:
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
- virtual GString *getPSFilter(const char *indent) { (void)indent; return NULL; }
- virtual GBool isBinary(GBool last = gTrue) { (void)last; return gFalse; }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
virtual GBool isEncoder() { return gTrue; }
private:
@@ -696,7 +696,7 @@ private:
class RunLengthEncoder: public FilterStream {
public:
- RunLengthEncoder(Stream *str);
+ RunLengthEncoder(Stream *strA);
virtual ~RunLengthEncoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
@@ -705,8 +705,8 @@ public:
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
- virtual GString *getPSFilter(const char *indent) { (void)indent; return NULL; }
- virtual GBool isBinary(GBool last = gTrue) { (void)last; return gFalse; }
+ virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
virtual GBool isEncoder() { return gTrue; }
private:
diff --git a/pdftops/T1Font.h b/pdftops/T1Font.h
index 9ead397f62..846d253e9f 100644
--- a/pdftops/T1Font.h
+++ b/pdftops/T1Font.h
@@ -26,8 +26,8 @@ class FontEncoding;
class T1FontEngine: public SFontEngine {
public:
- T1FontEngine(Display *display, Visual *visual, int depth,
- Colormap colormap, GBool aa, GBool aaHigh);
+ T1FontEngine(Display *displayA, Visual *visualA, int depthA,
+ Colormap colormapA, GBool aaA, GBool aaHighA);
GBool isOk() { return ok; }
virtual ~T1FontEngine();
@@ -35,7 +35,6 @@ private:
GBool aa; // use anti-aliasing?
GBool aaHigh; // use high-res anti-aliasing?
- GBool bigEndian;
GBool ok;
friend class T1FontFile;
@@ -47,8 +46,8 @@ private:
class T1FontFile: public SFontFile {
public:
- T1FontFile(T1FontEngine *engine, char *fontFileName,
- FontEncoding *fontEnc);
+ T1FontFile(T1FontEngine *engineA, char *fontFileName,
+ FontEncoding *fontEnc, double *bboxA);
GBool isOk() { return ok; }
virtual ~T1FontFile();
@@ -58,6 +57,7 @@ private:
int id; // t1lib font ID
char **enc;
char *encStr;
+ double bbox[4];
GBool ok;
friend class T1Font;
@@ -74,7 +74,7 @@ struct T1FontCacheTag {
class T1Font: public SFont {
public:
- T1Font(T1FontFile *fontFile, double *m);
+ T1Font(T1FontFile *fontFileA, double *m);
GBool isOk() { return ok; }
virtual ~T1Font();
virtual GBool drawChar(Drawable d, int w, int h, GC gc,
diff --git a/pdftops/TTFont.h b/pdftops/TTFont.h
index 68e5d97364..998087c9c7 100644
--- a/pdftops/TTFont.h
+++ b/pdftops/TTFont.h
@@ -9,20 +9,18 @@
#ifndef TTFONT_H
#define TTFONT_H
-#if HAVE_FREETYPE_FREETYPE_H
+#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
#ifdef __GNUC__
#pragma interface
#endif
-#ifdef VMS
-#include
-#include
-#else
-//~ This will be going away; the configure script will add
-//~ -I/freetype to CFLAGS.
+#if HAVE_FREETYPE_FREETYPE_H
#include
#include
+#else
+#include
+#include
#endif
#include "SFont.h"
@@ -31,8 +29,8 @@
class TTFontEngine: public SFontEngine {
public:
- TTFontEngine(Display *display, Visual *visual, int depth,
- Colormap colormap, GBool aa);
+ TTFontEngine(Display *displayA, Visual *visualA, int depthA,
+ Colormap colormapA, GBool aaA);
GBool isOk() { return ok; }
virtual ~TTFontEngine();
@@ -52,7 +50,7 @@ private:
class TTFontFile: public SFontFile {
public:
- TTFontFile(TTFontEngine *engine, char *fontFileName);
+ TTFontFile(TTFontEngine *engineA, char *fontFileName);
GBool isOk() { return ok; }
virtual ~TTFontFile();
@@ -77,7 +75,7 @@ struct TTFontCacheTag {
class TTFont: public SFont {
public:
- TTFont(TTFontFile *fontFile, double *m);
+ TTFont(TTFontFile *fontFileA, double *m);
GBool isOk() { return ok; }
virtual ~TTFont();
virtual GBool drawChar(Drawable d, int w, int h, GC gc,
@@ -101,6 +99,6 @@ private:
GBool ok;
};
-#endif // HAVE_FREETYPE_FREETYPE_H
+#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
#endif
diff --git a/pdftops/XRef.cxx b/pdftops/XRef.cxx
index d70b9f2097..de2db2f23b 100644
--- a/pdftops/XRef.cxx
+++ b/pdftops/XRef.cxx
@@ -43,18 +43,11 @@
#define defPermFlags 0xfffc
#endif
-//------------------------------------------------------------------------
-// The global xref table
-//------------------------------------------------------------------------
-
-XRef *xref = NULL;
-
//------------------------------------------------------------------------
// XRef
//------------------------------------------------------------------------
-XRef::XRef(BaseStream *str, GString *userPassword) {
- XRef *oldXref;
+XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) {
int pos;
int i;
@@ -64,13 +57,8 @@ XRef::XRef(BaseStream *str, GString *userPassword) {
streamEnds = NULL;
streamEndsLen = 0;
- // get rid of old xref (otherwise it will try to fetch the Root object
- // in the new document, using the old xref)
- oldXref = xref;
- xref = NULL;
-
// read the trailer
- this->str = str;
+ str = strA;
start = str->getStart();
pos = readTrailer();
@@ -78,7 +66,6 @@ XRef::XRef(BaseStream *str, GString *userPassword) {
// try to reconstruct the xref table
if (pos == 0) {
if (!(ok = constructXRef())) {
- xref = oldXref;
return;
}
@@ -98,22 +85,21 @@ XRef::XRef(BaseStream *str, GString *userPassword) {
size = 0;
entries = NULL;
if (!(ok = constructXRef())) {
- xref = oldXref;
return;
}
}
}
- // set up new xref table
- xref = this;
+ // now set the trailer dictionary's xref pointer so we can fetch
+ // indirect objects from it
+ trailerDict.getDict()->setXRef(this);
// check for encryption
#ifndef NO_DECRYPTION
encrypted = gFalse;
#endif
- if (checkEncrypted(userPassword)) {
+ if (checkEncrypted(ownerPassword, userPassword)) {
ok = gFalse;
- xref = oldXref;
return;
}
}
@@ -189,7 +175,8 @@ int XRef::readTrailer() {
// read trailer dict
obj.initNull();
- parser = new Parser(new Lexer(str->makeSubStream(start + pos1, -1, &obj)));
+ parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(start + pos1,
+ -1, &obj)));
parser->getObj(&trailerDict);
if (trailerDict.isDict()) {
trailerDict.dictLookupNF("Size", &obj);
@@ -221,7 +208,7 @@ GBool XRef::readXRef(int *pos) {
Object obj, obj2;
char s[20];
GBool more;
- int first, n, i, j;
+ int first, newSize, n, i, j;
int c;
// seek to xref in stream
@@ -233,35 +220,56 @@ GBool XRef::readXRef(int *pos) {
s[1] = (char)str->getChar();
s[2] = (char)str->getChar();
s[3] = (char)str->getChar();
- if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f'))
+ if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) {
goto err2;
+ }
// read xref
while (1) {
- while ((c = str->lookChar()) != EOF && isspace(c))
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
str->getChar();
- if (c == 't')
+ }
+ if (c == 't') {
break;
- for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i)
+ }
+ for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) {
s[i] = (char)c;
- if (i == 0)
+ }
+ if (i == 0) {
goto err2;
+ }
s[i] = '\0';
first = atoi(s);
- while ((c = str->lookChar()) != EOF && isspace(c))
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
str->getChar();
- for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i)
+ }
+ for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) {
s[i] = (char)c;
- if (i == 0)
+ }
+ if (i == 0) {
goto err2;
+ }
s[i] = '\0';
n = atoi(s);
- while ((c = str->lookChar()) != EOF && isspace(c))
+ while ((c = str->lookChar()) != EOF && isspace(c)) {
str->getChar();
+ }
+ // check for buggy PDF files with an incorrect (too small) xref
+ // table size
+ if (first + n > size) {
+ newSize = size + 256;
+ entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = -1;
+ entries[i].used = gFalse;
+ }
+ size = newSize;
+ }
for (i = first; i < first + n; ++i) {
for (j = 0; j < 20; ++j) {
- if ((c = str->getChar()) == EOF)
+ if ((c = str->getChar()) == EOF) {
goto err2;
+ }
s[j] = (char)c;
}
if (entries[i].offset < 0) {
@@ -269,16 +277,16 @@ GBool XRef::readXRef(int *pos) {
entries[i].offset = atoi(s);
s[16] = '\0';
entries[i].gen = atoi(&s[11]);
- if (s[17] == 'n')
+ if (s[17] == 'n') {
entries[i].used = gTrue;
- else if (s[17] == 'f')
+ } else if (s[17] == 'f') {
entries[i].used = gFalse;
- else
+ } else {
goto err2;
-#if 1 //~
- //~ PDF files of patents from the IBM Intellectual Property
- //~ Network have a bug: the xref table claims to start at 1
- //~ instead of 0.
+ }
+ // PDF files of patents from the IBM Intellectual Property
+ // Network have a bug: the xref table claims to start at 1
+ // instead of 0.
if (i == 1 && first == 1 &&
entries[1].offset == 0 && entries[1].gen == 65535 &&
!entries[1].used) {
@@ -286,21 +294,23 @@ GBool XRef::readXRef(int *pos) {
entries[0] = entries[1];
entries[1].offset = -1;
}
-#endif
}
}
}
// read prev pointer from trailer dictionary
obj.initNull();
- parser = new Parser(new Lexer(str->makeSubStream(str->getPos(), -1, &obj)));
+ parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(str->getPos(),
+ -1, &obj)));
parser->getObj(&obj);
- if (!obj.isCmd("trailer"))
+ if (!obj.isCmd("trailer")) {
goto err1;
+ }
obj.free();
parser->getObj(&obj);
- if (!obj.isDict())
+ if (!obj.isDict()) {
goto err1;
+ }
obj.getDict()->lookupNF("Prev", &obj2);
if (obj2.isInt()) {
*pos = obj2.getInt();
@@ -349,7 +359,7 @@ GBool XRef::constructXRef() {
// got trailer dictionary
if (!strncmp(p, "trailer", 7)) {
obj.initNull();
- parser = new Parser(new Lexer(
+ parser = new Parser(NULL, new Lexer(NULL,
str->makeSubStream(start + pos + 7, -1, &obj)));
if (!trailerDict.isNone())
trailerDict.free();
@@ -424,8 +434,9 @@ GBool XRef::constructXRef() {
}
#ifndef NO_DECRYPTION
-GBool XRef::checkEncrypted(GString *userPassword) {
- Object encrypt, ownerKey, userKey, permissions, fileID, fileID1;
+GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
+ Object encrypt, filterObj, versionObj, revisionObj, lengthObj;
+ Object ownerKey, userKey, permissions, fileID, fileID1;
GBool encrypted1;
GBool ret;
@@ -435,35 +446,68 @@ GBool XRef::checkEncrypted(GString *userPassword) {
trailerDict.dictLookup("Encrypt", &encrypt);
if ((encrypted1 = encrypt.isDict())) {
ret = gTrue;
- encrypt.dictLookup("O", &ownerKey);
- encrypt.dictLookup("U", &userKey);
- encrypt.dictLookup("P", &permissions);
- trailerDict.dictLookup("ID", &fileID);
- if (ownerKey.isString() && ownerKey.getString()->getLength() == 32 &&
- userKey.isString() && userKey.getString()->getLength() == 32 &&
- permissions.isInt() &&
- fileID.isArray()) {
- permFlags = permissions.getInt();
- fileID.arrayGet(0, &fileID1);
- if (fileID1.isString()) {
- if (Decrypt::makeFileKey(ownerKey.getString(), userKey.getString(),
- permFlags, fileID1.getString(),
- userPassword, fileKey)) {
- ret = gFalse;
+ encrypt.dictLookup("Filter", &filterObj);
+ if (filterObj.isName("Standard")) {
+ encrypt.dictLookup("V", &versionObj);
+ encrypt.dictLookup("R", &revisionObj);
+ encrypt.dictLookup("Length", &lengthObj);
+ encrypt.dictLookup("O", &ownerKey);
+ encrypt.dictLookup("U", &userKey);
+ encrypt.dictLookup("P", &permissions);
+ trailerDict.dictLookup("ID", &fileID);
+ if (versionObj.isInt() &&
+ revisionObj.isInt() &&
+ ownerKey.isString() && ownerKey.getString()->getLength() == 32 &&
+ userKey.isString() && userKey.getString()->getLength() == 32 &&
+ permissions.isInt() &&
+ fileID.isArray()) {
+ encVersion = versionObj.getInt();
+ encRevision = revisionObj.getInt();
+ if (lengthObj.isInt()) {
+ keyLength = lengthObj.getInt() / 8;
+ } else {
+ keyLength = 5;
+ }
+ permFlags = permissions.getInt();
+ if (encVersion >= 1 && encVersion <= 2 &&
+ encRevision >= 2 && encRevision <= 3) {
+ fileID.arrayGet(0, &fileID1);
+ if (fileID1.isString()) {
+ if (Decrypt::makeFileKey(encVersion, encRevision, keyLength,
+ ownerKey.getString(), userKey.getString(),
+ permFlags, fileID1.getString(),
+ ownerPassword, userPassword, fileKey,
+ &ownerPasswordOk)) {
+ if (ownerPassword && !ownerPasswordOk) {
+ error(-1, "Incorrect owner password");
+ }
+ ret = gFalse;
+ } else {
+ error(-1, "Incorrect password");
+ }
+ } else {
+ error(-1, "Weird encryption info");
+ }
+ fileID1.free();
} else {
- error(-1, "Incorrect user password");
+ error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
+ encVersion, encRevision);
}
} else {
error(-1, "Weird encryption info");
}
- fileID1.free();
+ fileID.free();
+ permissions.free();
+ userKey.free();
+ ownerKey.free();
+ lengthObj.free();
+ revisionObj.free();
+ versionObj.free();
} else {
- error(-1, "Weird encryption info");
+ error(-1, "Unknown security handler '%s'",
+ filterObj.isName() ? filterObj.getName() : "???");
}
- ownerKey.free();
- userKey.free();
- permissions.free();
- fileID.free();
+ filterObj.free();
}
encrypt.free();
@@ -473,52 +517,50 @@ GBool XRef::checkEncrypted(GString *userPassword) {
return ret;
}
#else
-GBool XRef::checkEncrypted(GString *userPassword) {
+GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
Object obj;
GBool encrypted;
trailerDict.dictLookup("Encrypt", &obj);
if ((encrypted = !obj.isNull())) {
- error(-1, "PDF file is encrypted and cannot be displayed");
- error(-1, "* Decryption support is currently not included in xpdf");
- error(-1, "* due to legal restrictions: the U.S.A. still has bogus");
- error(-1, "* export controls on cryptography software.");
+ error(-1, "PDF file is encrypted and this version of the Xpdf tools");
+ error(-1, "was built without decryption support.");
}
obj.free();
return encrypted;
}
#endif
-GBool XRef::okToPrint() {
+GBool XRef::okToPrint(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permPrint)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permPrint)) {
return gFalse;
}
#endif
return gTrue;
}
-GBool XRef::okToChange() {
+GBool XRef::okToChange(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permChange)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permChange)) {
return gFalse;
}
#endif
return gTrue;
}
-GBool XRef::okToCopy() {
+GBool XRef::okToCopy(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permCopy)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permCopy)) {
return gFalse;
}
#endif
return gTrue;
}
-GBool XRef::okToAddNotes() {
+GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if (!(permFlags & permNotes)) {
+ if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permNotes)) {
return gFalse;
}
#endif
@@ -539,7 +581,7 @@ Object *XRef::fetch(int num, int gen, Object *obj) {
e = &entries[num];
if (e->gen == gen && e->offset >= 0) {
obj1.initNull();
- parser = new Parser(new Lexer(
+ parser = new Parser(this, new Lexer(this,
str->makeSubStream(start + e->offset, -1, &obj1)));
parser->getObj(&obj1);
parser->getObj(&obj2);
@@ -548,7 +590,8 @@ Object *XRef::fetch(int num, int gen, Object *obj) {
obj2.isInt() && obj2.getInt() == gen &&
obj3.isCmd("obj")) {
#ifndef NO_DECRYPTION
- parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, num, gen);
+ parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength,
+ num, gen);
#else
parser->getObj(obj);
#endif
@@ -569,20 +612,20 @@ Object *XRef::getDocInfo(Object *obj) {
return trailerDict.dictLookup("Info", obj);
}
-int XRef::getStreamEnd(int start) {
+int XRef::getStreamEnd(int streamStart) {
int a, b, m;
if (streamEndsLen == 0 ||
- start > streamEnds[streamEndsLen - 1]) {
+ streamStart > streamEnds[streamEndsLen - 1]) {
return -1;
}
a = -1;
b = streamEndsLen - 1;
- // invariant: streamEnds[a] < start <= streamEnds[b]
+ // invariant: streamEnds[a] < streamStart <= streamEnds[b]
while (b - a > 1) {
m = (a + b) / 2;
- if (start <= streamEnds[m]) {
+ if (streamStart <= streamEnds[m]) {
b = m;
} else {
a = m;
diff --git a/pdftops/XRef.h b/pdftops/XRef.h
index e2260d0c33..35306bba83 100644
--- a/pdftops/XRef.h
+++ b/pdftops/XRef.h
@@ -33,7 +33,7 @@ class XRef {
public:
// Constructor. Read xref table from stream.
- XRef(BaseStream *str, GString *userPassword);
+ XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword);
// Destructor.
~XRef();
@@ -49,10 +49,10 @@ public:
#endif
// Check various permissions.
- GBool okToPrint();
- GBool okToChange();
- GBool okToCopy();
- GBool okToAddNotes();
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse);
+ GBool okToChange(GBool ignoreOwnerPW = gFalse);
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse);
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse);
// Get catalog object.
Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); }
@@ -75,7 +75,7 @@ public:
// Get end position for a stream in a damaged file.
// Returns -1 if unknown or file is not damaged.
- int getStreamEnd(int start);
+ int getStreamEnd(int streamStart);
private:
@@ -93,20 +93,18 @@ private:
int streamEndsLen; // number of valid entries in streamEnds
#ifndef NO_DECRYPTION
GBool encrypted; // true if file is encrypted
+ int encVersion; // encryption algorithm
+ int encRevision; // security handler revision
+ int keyLength; // length of key, in bytes
int permFlags; // permission bits
Guchar fileKey[16]; // file decryption key
+ GBool ownerPasswordOk; // true if owner password is correct
#endif
int readTrailer();
GBool readXRef(int *pos);
GBool constructXRef();
- GBool checkEncrypted(GString *userPassword);
+ GBool checkEncrypted(GString *ownerPassword, GString *userPassword);
};
-//------------------------------------------------------------------------
-// The global xref table
-//------------------------------------------------------------------------
-
-extern XRef *xref;
-
#endif
diff --git a/pdftops/config.h b/pdftops/config.h
index ff79d1f889..872aadfd03 100644
--- a/pdftops/config.h
+++ b/pdftops/config.h
@@ -17,14 +17,14 @@
//------------------------------------------------------------------------
// xpdf version
-#define xpdfVersion "0.92"
+#define xpdfVersion "0.93a"
// supported PDF version
-#define supportedPDFVersionStr "1.3"
-#define supportedPDFVersionNum 1.3
+#define supportedPDFVersionStr "1.4"
+#define supportedPDFVersionNum 1.4
// copyright notice
-#define xpdfCopyright "Copyright 1996-2000 Derek B. Noonburg"
+#define xpdfCopyright "Copyright 1996-2001 Derek B. Noonburg"
// default paper size (in points) for PostScript output
#ifdef A4_PAPER
@@ -35,13 +35,25 @@
#define defPaperHeight 792
#endif
-// config file name
+// user config file name, relative to the user's home directory
#if defined(VMS)
-#define xpdfConfigFile "xpdfrc"
+#define xpdfUserConfigFile "xpdfrc"
#else
-#define xpdfConfigFile ".xpdfrc"
+#define xpdfUserConfigFile ".xpdfrc"
#endif
+#ifndef SYSTEM_XPDFRC
+# define SYSTEM_XPDFRC CUPS_SERVERROOT "/pdftops.conf"
+#endif // SYSTEM_XPDFRC
+
+// system config file name (set via the configure script)
+#define xpdfSysConfigFile SYSTEM_XPDFRC
+
+// Support Unicode/etc.
+#define JAPANESE_SUPPORT 1
+#define CHINESE_GB_SUPPORT 1
+#define CHINESE_CNS_SUPPORT 1
+
//------------------------------------------------------------------------
// X-related constants
//------------------------------------------------------------------------
@@ -58,6 +70,9 @@
// number of TrueType (FreeType) fonts to cache
#define ttFontCacheSize 32
+// number of FreeType (TrueType and Type 1) fonts to cache
+#define ftFontCacheSize 32
+
//------------------------------------------------------------------------
// popen
//------------------------------------------------------------------------
@@ -67,7 +82,7 @@
#define pclose _pclose
#endif
-#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(WIN32) || defined(__DJGPP__) || defined(__CYGWIN32) || defined(MACOS)
+#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(__CYGWIN32__) || defined(MACOS)
#define POPEN_READ_MODE "rb"
#else
#define POPEN_READ_MODE "r"
diff --git a/pdftops/configure.in b/pdftops/configure.in
deleted file mode 100644
index 8ba7984758..0000000000
--- a/pdftops/configure.in
+++ /dev/null
@@ -1,203 +0,0 @@
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT(xpdf/xpdf.cc)
-
-dnl ##### Optional features.
-OPTIONS=""
-AC_ARG_ENABLE(a4-paper,
-[ --enable-a4-paper use A4 paper size instead of Letter for
- PostScript output],
-OPTIONS="$OPTIONS -DA4_PAPER")
-AC_ARG_ENABLE(japanese,
-[ --enable-japanese enable Japanese font support],
-OPTIONS="$OPTIONS -DJAPANESE_SUPPORT")
-AC_ARG_ENABLE(no-text-select,
-[ --enable-no-text-select do not allow text selection],
-OPTIONS="$OPTIONS -DNO_TEXT_SELECT")
-AC_ARG_WITH(gzip,
-[ --with-gzip use gzip instead of uncompress],
-OPTIONS="$OPTIONS -DUSE_GZIP")
-AC_SUBST(OPTIONS)
-
-dnl ##### Checks for programs.
-AC_PROG_CC
-AC_ISC_POSIX
-AM_PROG_CC_STDC
-#if test -z "$CXX" -a "$CC" = "gcc"; then
-# CXX="gcc"
-#fi
-AC_PROG_CXX
-AC_PROG_INSTALL
-AC_PROG_RANLIB
-
-dnl ##### Default values for Unix.
-EXE=""
-LIBPREFIX="lib"
-AR="ar rc"
-UP_DIR=""
-
-dnl ##### Check for OS/2.
-AC_CACHE_CHECK([for OS/2 (with EMX)],
-xpdf_cv_sys_os2,
-[AC_TRY_COMPILE([],
-[__EMX__],
-xpdf_cv_sys_os2=yes, xpdf_cv_sys_os2=no)])
-if test "$xpdf_cv_sys_os2" = yes; then
- EXE=".exe"
- LIBPREFIX=""
- AR="ar -rc"
-fi
-
-dnl ##### Check for DOS (with DJGPP).
-AC_CACHE_CHECK([for DOS (with DJGPP)],
-xpdf_cv_sys_dos,
-[AC_TRY_COMPILE([],
-[__DJGPP__],
-xpdf_cv_sys_dos=yes, xpdf_cv_sys_dos=no)])
-if test "$xpdf_cv_sys_dos" = yes; then
- EXE=".exe"
- LIBPREFIX="lib"
- AR="ar -rc"
- UP_DIR="../"
-fi
-
-dnl ##### Do substitutions.
-AC_SUBST(EXE)
-AC_SUBST(LIBPREFIX)
-AC_SUBST(AR)
-AC_SUBST(UP_DIR)
-
-dnl ##### Checks for header files.
-AC_PATH_XTRA
-AC_HEADER_DIRENT
-
-dnl ##### Look for header that defines fd_set.
-AC_MSG_CHECKING([fd_set and sys/select.h or sys/bsdtypes.h])
-AC_TRY_COMPILE([#include ],
- [fd_set fds;], xpdf_ok=yes, xpdf_ok=no)
-if test $xpdf_ok = yes; then
- AC_MSG_RESULT([not needed])
-else
- AC_TRY_COMPILE([#include
-#include ],
- [fd_set fds;], xpdf_ok=yes, xpdf_ok=no)
- if test $xpdf_ok = yes; then
- AC_DEFINE(HAVE_SYS_SELECT_H)
- AC_MSG_RESULT([need sys/select.h])
- else
- AC_TRY_COMPILE([#include
-#include ],
- [fd_set fds;], xpdf_ok=yes, xpdf_ok=no)
- if test $xpdf_ok = yes; then
- AC_DEFINE(HAVE_SYS_BSDTYPES_H)
- AC_MSG_RESULT([need sys/bsdtypes.h])
- else
- AC_MSG_RESULT([problem])
- fi
- fi
-fi
-
-dnl ##### Look for header that defines FD_ZERO.
-AC_MSG_CHECKING([FD_ZERO and strings.h or bstring.h])
-AC_TRY_COMPILE([#include
-#ifdef HAVE_SYS_SELECT_H
-#include
-#endif],
-[fd_set fds; FD_ZERO(&fds);], xpdf_ok=yes, xpdf_ok=no)
-if test $xpdf_ok = yes; then
- AC_MSG_RESULT([not needed])
-else
- AC_TRY_COMPILE([#include
-#include
-#ifdef HAVE_SYS_SELECT_H
-#include
-#endif],
- [fd_set fds; FD_ZERO(&fds);], xpdf_ok=yes, xpdf_ok=no)
- if test $xpdf_ok = yes; then
- AC_DEFINE(HAVE_STRINGS_H)
- AC_MSG_RESULT([need strings.h])
- else
- AC_TRY_COMPILE([#include
-#include
-#ifdef HAVE_SYS_SELECT_H
-#include
-#endif],
- [fd_set fds; FD_ZERO(&fds);], xpdf_ok=yes, xpdf_ok=no)
- if test $xpdf_ok = yes; then
- AC_DEFINE(HAVE_BSTRING_H)
- AC_MSG_RESULT([need bstring.h])
- else
- AC_MSG_RESULT([problem])
- fi
- fi
-fi
-
-dnl ##### Look for rewinddir.
-AC_CHECK_FUNCS(rewinddir)
-if test $ac_cv_func_rewinddir = no; then
- AC_CHECK_LIB(cposix, rewinddir)
-fi
-
-dnl ##### Checks for library functions.
-AC_CHECK_FUNCS(popen)
-
-dnl ##### Check select argument type: on HP-UX before version 10, select
-dnl ##### takes (int *) instead of (fd_set *).
-AC_LANG_CPLUSPLUS
-AC_CACHE_CHECK([whether select takes fd_set arguments],
-xpdf_cv_func_select_arg,
-[AC_TRY_COMPILE([#include
-#include
-#ifdef HAVE_SYS_SELECT_H
-#include
-#endif],
-[fd_set fds;
-select(1, &fds, &fds, &fds, 0);],
-xpdf_cv_func_select_arg=yes, xpdf_cv_func_select_arg=no)])
-if test "$xpdf_cv_func_select_arg" != yes; then
- AC_DEFINE(SELECT_TAKES_INT)
-fi
-AC_LANG_C
-
-dnl ##### Check for libXpm.
-if test -z "$no_x"; then
- smr_CHECK_LIB(Xpm, Xpm, [pixmap library, used only for icon],
- XpmCreatePixmapFromData, X11/xpm.h,
- $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS, $X_CFLAGS)
- AC_SUBST(Xpm_LIBS)
- AC_SUBST(Xpm_CFLAGS)
-fi
-
-dnl ##### Check for t1lib.
-if test -z "$no_x"; then
- smr_CHECK_LIB(t1, t1, [Type 1 font rasterizer],
- T1_InitLib, t1lib.h,
- $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS -lm, $X_CFLAGS)
- AC_SUBST(t1_LIBS)
- AC_SUBST(t1_CFLAGS)
- smr_CHECK_LIB(t1x, t1x, [Type 1 font rasterizer],
- T1_SetX11Params, t1libx.h,
- $X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS $t1_LIBS -lm,
- $X_CFLAGS $t1_CFLAGS)
- AC_SUBST(t1x_LIBS)
- AC_SUBST(t1x_CFLAGS)
-fi
-
-dnl ##### Disable X-specific stuff in top-level Makefile.
-if test -n "$no_x"; then
- X="#"
- XPDF_TARGET="all-no-x"
-else
- X=""
- XPDF_TARGET="all"
-fi
-AC_SUBST(X)
-AC_SUBST(XPDF_TARGET)
-
-dnl ##### Write the makefiles.
-AC_OUTPUT(Makefile xpdf/Makefile ltk/Makefile goo/Makefile)
-
-dnl ##### Warn user if X is missing.
-if test -n "$no_x"; then
- AC_MSG_WARN([Couldn't find X -- you will be able to compile
- pdftops, pdftotext, pdfinfo, and pdfimages, but not xpdf])
-fi
diff --git a/pdftops/gfile.cxx b/pdftops/gfile.cxx
index 5e3781793e..e6428b71b2 100644
--- a/pdftops/gfile.cxx
+++ b/pdftops/gfile.cxx
@@ -38,6 +38,13 @@
# include
#endif // HAVE_LIBCUPS
+#ifdef __sun
+// Solaris doesn't define mkstemp()...
+extern "C" {
+extern int mkstemp(char *);
+}
+#endif // __sun
+
// Some systems don't define this, so just make it something reasonably
// large.
#ifndef PATH_MAX
@@ -450,23 +457,7 @@ time_t getModTime(const char *fileName) {
}
GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext) {
-#ifdef HAVE_LIBCUPS
- char filename[1024]; // Name of temporary file...
- int fd; // File descriptor...
-
-
- (void)ext;
-
- // Use the CUPS temporary file function on all platforms...
- if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
- return (gFalse);
-
- // Make the file descriptor a FILE *, and copy the temp filename...
- *f = fdopen(fd, mode);
- *name = new GString(filename);
-
- return (gTrue);
-#elif defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
+#if defined(VMS) || defined(__EMX__) || defined(WIN32) || defined(ACORN) || defined(MACOS)
//---------- non-Unix ----------
char *s;
@@ -488,10 +479,36 @@ GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext)
return gTrue;
#else
//---------- Unix ----------
- char *s, *p;
+ char *s;
int fd;
+ // MRS: Currently there is no standard function for creating a temporary
+ // file with an extension; this is required when uncompressing
+ // LZW data using the uncompress program on some UNIX, which is
+ // looking for a ".Z" extension on the temporary filename. Sooo,
+ // when you print an *OLD* PDF file that uses LZW compression,
+ // the tmpnam() function is usually the one that is called to
+ // create the temporary file. Under *BSD, the safer mkstemps()
+ // function is used instead.
+ //
+ // That said, all CUPS filters are run with TMPDIR pointing to
+ // a private temporary directory, which by default is only
+ // accessible to the 'lp' user. Also, most files use Flate
+ // compression now and will be able to use the (safer)
+ // mkstemp() function for any temporary files...
+
if (ext) {
+# if HAVE_MKSTEMPS
+ if ((s = getenv("TMPDIR"))) {
+ *name = new GString(s);
+ } else {
+ *name = new GString("/tmp");
+ }
+ (*name)->append("/XXXXXX");
+ (*name)->append(ext);
+ fd = mkstemps((*name)->getCString(), strlen(ext));
+# else // HAVE_MKSTEMPS
+ char *p;
if (!(s = tmpnam(NULL))) {
return gFalse;
}
@@ -502,6 +519,7 @@ GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext)
}
(*name)->append(ext);
fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
+# endif // HAVE_MKSTEMPS
} else {
# if HAVE_MKSTEMP
if ((s = getenv("TMPDIR"))) {
diff --git a/pdftops/pdftops.cxx b/pdftops/pdftops.cxx
index 7002302a69..fe107f9450 100644
--- a/pdftops/pdftops.cxx
+++ b/pdftops/pdftops.cxx
@@ -26,63 +26,14 @@
#include "Error.h"
#include "config.h"
-#ifdef HAVE_LIBCUPS
-# include
-#endif /* HAVE_LIBCUPS */
-
-static int firstPage = 1;
-static int lastPage = 0;
-static GBool noEmbedFonts = gFalse;
-static GBool doForm = gFalse;
-static char userPassword[33] = "";
-static GBool printVersion = gFalse;
-static GBool printHelp = gFalse;
-
-static ArgDesc argDesc[] = {
- {"-f", argInt, &firstPage, 0,
- "first page to print"},
- {"-l", argInt, &lastPage, 0,
- "last page to print"},
- {"-paperw", argInt, &paperWidth, 0,
- "paper width, in points"},
- {"-paperh", argInt, &paperHeight, 0,
- "paper height, in points"},
- {"-level1", argFlag, &psOutLevel1, 0,
- "generate Level 1 PostScript"},
- {"-level1sep", argFlag, &psOutLevel1Sep, 0,
- "generate Level 1 separable PostScript"},
- {"-eps", argFlag, &psOutEPS, 0,
- "generate Encapsulated PostScript (EPS)"},
-#if OPI_SUPPORT
- {"-opi", argFlag, &psOutOPI, 0,
- "generate OPI comments"},
-#endif
- {"-noemb", argFlag, &noEmbedFonts, 0,
- "don't embed Type 1 fonts"},
- {"-form", argFlag, &doForm, 0,
- "generate a PostScript form"},
- {"-upw", argString, userPassword, sizeof(userPassword),
- "user password (for encrypted files)"},
- {"-q", argFlag, &errQuiet, 0,
- "don't print any messages or errors"},
- {"-v", argFlag, &printVersion, 0,
- "print copyright and version info"},
- {"-h", argFlag, &printHelp, 0,
- "print usage information"},
- {"-help", argFlag, &printHelp, 0,
- "print usage information"},
- {NULL}
-};
+#include
int main(int argc, char *argv[]) {
- PDFDoc *doc;
- GString *fileName;
- GString *psFileName;
- GString *userPW;
- PSOutputDev *psOut;
- GBool ok;
- char *p;
-#ifdef HAVE_LIBCUPS
+ PDFDoc *doc;
+ GString *fileName;
+ GString *psFileName;
+ PSOutLevel level;
+ PSOutputDev *psOut;
int num_options;
cups_option_t *options;
ppd_file_t *ppd;
@@ -92,68 +43,49 @@ int main(int argc, char *argv[]) {
char tempfile[1024];
char buffer[8192];
int bytes;
+ int width, length;
- // See if we are being run as a filter...
- if (getenv("PPD") && getenv("SOFTWARE")) {
- // Yes, make sure status messages are not buffered...
- setbuf(stderr, NULL);
+ // Make sure status messages are not buffered...
+ setbuf(stderr, NULL);
- // Send all error messages...
- errQuiet = 0;
+ // Send all error messages...
+ errQuiet = 0;
+
+ // Make sure we have the right number of arguments for CUPS!
+ if (argc < 6 || argc > 7) {
+ fputs("Usage: pdftops job user title copies options [filename]\n", stderr);
+ return (1);
+ }
- // Make sure we have the right number of arguments for CUPS!
- if (argc < 6 || argc > 7) {
- fputs("Usage: pdftops job user title copies options [filename]\n", stderr);
+ // Copy stdin if needed...
+ if (argc == 6) {
+ if ((fp = fopen(cupsTempFile(tempfile, sizeof(tempfile)), "w")) == NULL) {
+ perror("ERROR: Unable to copy PDF file");
return (1);
}
- // Copy stdin if needed...
- if (argc == 6) {
- if ((fp = fopen(cupsTempFile(tempfile, sizeof(tempfile)), "w")) == NULL) {
- perror("ERROR: Unable to copy PDF file");
- return (1);
- }
+ fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n",
+ tempfile);
- fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n",
- tempfile);
+ while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ fwrite(buffer, 1, bytes, fp);
+ fclose(fp);
- while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
- fwrite(buffer, 1, bytes, fp);
- fclose(fp);
-
- fileName = new GString(tempfile);
- } else {
- fileName = new GString(argv[6]);
- tempfile[0] = '\0';
- }
+ fileName = new GString(tempfile);
} else {
+ fileName = new GString(argv[6]);
tempfile[0] = '\0';
-#endif // HAVE_LIBCUPS
- // parse args
- ok = parseArgs(argDesc, &argc, argv);
- if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) {
- fprintf(stderr, "pdftops version %s\n", xpdfVersion);
- fprintf(stderr, "%s\n", xpdfCopyright);
- if (!printVersion) {
- printUsage("pdftops", " []", argDesc);
- }
- exit(1);
- }
- if (psOutLevel1 && psOutLevel1Sep) {
- fprintf(stderr, "Error: use -level1 or -level1sep, not both.\n");
- exit(1);
- }
- if (doForm && (psOutLevel1 || psOutLevel1Sep)) {
- fprintf(stderr, "Error: forms are only available with Level 2 output.\n");
- exit(1);
- }
- fileName = new GString(argv[1]);
-#ifdef HAVE_LIBCUPS
}
+ // Default to "Universal" size - min of A4 and Letter...
+ width = 595;
+ length = 792;
+ level = psLevel2;
+
// Get PPD and initialize options as needed...
- if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL) {
+ if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL)
+ {
fprintf(stderr, "DEBUG: pdftops - opened PPD file \"%s\"...\n", getenv("PPD"));
ppdMarkDefaults(ppd);
@@ -161,103 +93,55 @@ int main(int argc, char *argv[]) {
cupsMarkOptions(ppd, num_options, options);
cupsFreeOptions(num_options, options);
- if ((size = ppdPageSize(ppd, NULL)) != NULL) {
- paperWidth = (int)size->width;
- paperHeight = (int)size->length;
+ if ((size = ppdPageSize(ppd, NULL)) != NULL)
+ {
+ width = (int)size->width;
+ length = (int)size->length;
}
- psOutLevel1 = ppd->language_level == 1;
-
- fprintf(stderr, "DEBUG: pdftops - psOutLevel1 = %d, paperWidth = %d, paperHeight = %d\n",
- psOutLevel1, paperWidth, paperHeight);
+ level = ppd->language_level == 1 ? psLevel1 : psLevel2;
ppdClose(ppd);
}
-#endif // HAVE_LIBCUPS
+
+ fprintf(stderr, "DEBUG: pdftops - level = %d, width = %d, length = %d\n",
+ level, width, length);
// init error file
errorInit();
// read config file
-#ifdef HAVE_LIBCUPS
- if ((server_root = getenv("CUPS_SERVERROOT")) != NULL) {
- sprintf(tempfile, "%s/pdftops.conf", server_root);
- initParams(tempfile);
- } else
-#endif /* HAVE_LIBCUPS */
- initParams(xpdfConfigFile);
+ if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+ server_root = CUPS_SERVERROOT;
+
+ sprintf(tempfile, "%s/pdftops.conf", server_root);
+ initParams("", tempfile);
// open PDF file
- xref = NULL;
- if (userPassword[0]) {
- userPW = new GString(userPassword);
- } else {
- userPW = NULL;
- }
- doc = new PDFDoc(fileName, userPW);
- if (userPW) {
- delete userPW;
- }
- if (!doc->isOk()) {
- goto err1;
- }
+ doc = new PDFDoc(fileName, NULL, NULL, getenv("DEBUG") != NULL);
// check for print permission
- if (!doc->okToPrint()) {
- error(-1, "Printing this document is not allowed.");
- goto err1;
- }
-
-#ifdef HAVE_LIBCUPS
- if (getenv("PPD") && getenv("SOFTWARE")) {
- // CUPS always needs every page and writes to stdout...
+ if (doc->isOk() && doc->okToPrint())
+ {
+ // CUPS always writes to stdout...
psFileName = new GString("-");
- firstPage = 1;
- lastPage = doc->getNumPages();
- } else {
-#endif // HAVE_LIBCUPS
-
- // construct PostScript file name
- if (argc == 3) {
- psFileName = new GString(argv[2]);
- } else {
- p = fileName->getCString() + fileName->getLength() - 4;
- if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF"))
- psFileName = new GString(fileName->getCString(),
- fileName->getLength() - 4);
- else
- psFileName = fileName->copy();
- psFileName->append(psOutEPS ? ".eps" : ".ps");
- }
- // get page range
- if (firstPage < 1)
- firstPage = 1;
- if (lastPage < 1 || lastPage > doc->getNumPages())
- lastPage = doc->getNumPages();
- if (doForm)
- lastPage = firstPage;
+ // write PostScript file
+ psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(),
+ doc->getCatalog(), 1, doc->getNumPages(),
+ level, psModePS, 0, 1, 1, width, length);
+ if (psOut->isOk())
+ doc->displayPages(psOut, 1, doc->getNumPages(), 72, 0, gFalse);
+ delete psOut;
- // check for multi-page EPS
- if (psOutEPS && firstPage != lastPage) {
- error(-1, "EPS files can only contain one page.");
- goto err2;
+ // clean up
+ delete psFileName;
}
-#ifdef HAVE_LIBCUPS
+ else
+ {
+ error(-1, "Unable to print this document.");
}
-#endif // HAVE_LIBCUPS
-
- // write PostScript file
- psOut = new PSOutputDev(psFileName->getCString(), doc->getCatalog(),
- firstPage, lastPage, !noEmbedFonts, doForm);
- if (psOut->isOk())
- doc->displayPages(psOut, firstPage, lastPage, 72, 0, gFalse);
- delete psOut;
- // clean up
- err2:
- delete psFileName;
- err1:
delete doc;
freeParams();
@@ -265,11 +149,9 @@ int main(int argc, char *argv[]) {
Object::memCheck(stderr);
gMemReport(stderr);
-#ifdef HAVE_LIBCUPS
// Remove temp file if needed...
if (tempfile[0])
unlink(tempfile);
-#endif /* HAVE_LIBCUPS */
return 0;
}
diff --git a/ppd/Makefile b/ppd/Makefile
index 117df28abb..5230f58443 100644
--- a/ppd/Makefile
+++ b/ppd/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.8.2.1 2001/05/13 18:38:30 mike Exp $"
+# "$Id: Makefile,v 1.8.2.2 2001/12/26 16:52:47 mike Exp $"
#
# PPD file makefile for the Common UNIX Printing System (CUPS).
#
@@ -28,8 +28,9 @@ include ../Makedefs
# PPD files...
#
-FILES = deskjet.ppd deskjet2.ppd epson9.ppd epson24.ppd laserjet.ppd \
- okidata9.ppd okidat24.ppd stcolor.ppd stphoto.ppd
+FILES = deskjet.ppd deskjet2.ppd dymo.ppd epson9.ppd epson24.ppd \
+ laserjet.ppd okidata9.ppd okidat24.ppd stcolor.ppd \
+ stcolor2.ppd stphoto.ppd stphoto2.ppd
#
@@ -51,11 +52,12 @@ clean:
#
install:
- -$(MKDIR) $(DATADIR)/model
- $(CHMOD) ugo+rx $(DATADIR)/model
- $(INSTALL_DATA) $(FILES) $(DATADIR)/model
+ $(INSTALL_DIR) $(DATADIR)/model
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/model; \
+ done
#
-# End of "$Id: Makefile,v 1.8.2.1 2001/05/13 18:38:30 mike Exp $".
+# End of "$Id: Makefile,v 1.8.2.2 2001/12/26 16:52:47 mike Exp $".
#
diff --git a/ppd/deskjet2.ppd b/ppd/deskjet2.ppd
index d6f487b9dd..8b86447a70 100644
--- a/ppd/deskjet2.ppd
+++ b/ppd/deskjet2.ppd
@@ -1,6 +1,6 @@
*PPD-Adobe: "4.3"
*%
-*% "$Id: deskjet2.ppd,v 1.1.2.1 2001/05/13 18:38:30 mike Exp $"
+*% "$Id: deskjet2.ppd,v 1.1.2.2 2001/12/26 16:52:47 mike Exp $"
*%
*% Second sample HP DeskJet driver PPD file for the Common UNIX Printing
*% System (CUPS).
@@ -161,7 +161,7 @@
*CloseUI: *ColorModel
*OpenUI *Duplex/Double-Sided Printing: PickOne
-*OrderDependency: 20 AnySetup *Duplex
+*OrderDependency: 20 PageSetup *Duplex
*DefaultDuplex: None
*Duplex None/Off: "<>setpagedevice"
*Duplex DuplexNoTumble/Long Edge (Standard): "<>setpagedevice"
@@ -213,5 +213,5 @@
*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
*Font ZapfDingbats: Special "(001.004S)" Standard ROM
*%
-*% End of "$Id: deskjet2.ppd,v 1.1.2.1 2001/05/13 18:38:30 mike Exp $".
+*% End of "$Id: deskjet2.ppd,v 1.1.2.2 2001/12/26 16:52:47 mike Exp $".
*%
diff --git a/ppd/dymo.ppd b/ppd/dymo.ppd
index cbc619809e..b0ab6c9cbb 100644
--- a/ppd/dymo.ppd
+++ b/ppd/dymo.ppd
@@ -1,6 +1,6 @@
*PPD-Adobe: "4.3"
*%
-*% "$Id: dymo.ppd,v 1.4 2001/07/18 18:18:30 mike Exp $"
+*% "$Id: dymo.ppd,v 1.4.2.1 2001/12/26 16:52:47 mike Exp $"
*%
*% Sample DYMO label printer driver PPD file for the Common UNIX Printing
*% System (CUPS).
@@ -151,5 +151,5 @@
*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
*Font ZapfDingbats: Special "(001.004S)" Standard ROM
*%
-*% End of "$Id: dymo.ppd,v 1.4 2001/07/18 18:18:30 mike Exp $".
+*% End of "$Id: dymo.ppd,v 1.4.2.1 2001/12/26 16:52:47 mike Exp $".
*%
diff --git a/pstoraster/Makefile b/pstoraster/Makefile
index b3bffac57d..fbc39912e7 100644
--- a/pstoraster/Makefile
+++ b/pstoraster/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.31.2.1 2001/05/13 18:38:31 mike Exp $"
+# "$Id: Makefile,v 1.31.2.2 2001/12/26 16:52:48 mike Exp $"
#
# GNU Ghostscript makefile for the Common UNIX Printing System (CUPS).
#
@@ -376,14 +376,12 @@ clean:
#
install: $(TARGETS)
- -$(MKDIR) $(SERVERBIN)/filter
- $(CHMOD) ugo+rx $(SERVERBIN)
- $(CHMOD) ugo+rx $(SERVERBIN)/filter
+ $(INSTALL_DIR) $(SERVERBIN)/filter
$(INSTALL_BIN) pstoraster $(SERVERBIN)/filter
- -$(MKDIR) $(DATADIR)/pstoraster
- $(CHMOD) ugo+rx $(DATADIR)
- $(CHMOD) ugo+rx $(DATADIR)/pstoraster
- $(INSTALL_DATA) $(DFILES) $(DATADIR)/pstoraster
+ $(INSTALL_DIR) $(DATADIR)/pstoraster
+ for file in $(DFILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/pstoraster; \
+ done
#
@@ -419,6 +417,16 @@ pstoraster: pstoraster.o libgs.a ../Makedefs ../cups/$(LIBCUPS)
$(LINKCUPSIMAGE) $(IMGLIBS) $(DSOLIBS) $(LIBS) -lm
+#
+# purify - target to test Ghostscript to see how leaky it is...
+#
+
+purify: pstoraster.o libgs.a ../Makedefs ../cups/$(LIBCUPS)
+ echo Linking $@...
+ purify $(CC) $(LDFLAGS) -o pstoraster.pure pstoraster.o libgs.a \
+ $(LINKCUPSIMAGE) $(IMGLIBS) $(DSOLIBS) $(LIBS) -lm
+
+
#
# Generate dependencies for Ghostscript source files...
#
@@ -442,5 +450,5 @@ include Dependencies
#
-# End of "$Id: Makefile,v 1.31.2.1 2001/05/13 18:38:31 mike Exp $".
+# End of "$Id: Makefile,v 1.31.2.2 2001/12/26 16:52:48 mike Exp $".
#
diff --git a/pstoraster/gdevcups.c b/pstoraster/gdevcups.c
index 187ec41de0..d3e6147379 100644
--- a/pstoraster/gdevcups.c
+++ b/pstoraster/gdevcups.c
@@ -1,5 +1,5 @@
/*
- * "$Id: gdevcups.c,v 1.43 2001/03/29 14:58:54 mike Exp $"
+ * "$Id: gdevcups.c,v 1.43.2.1 2001/12/26 16:52:48 mike Exp $"
*
* GNU Ghostscript raster output driver for the Common UNIX Printing
* System (CUPS).
@@ -324,8 +324,8 @@ cups_get_matrix(gx_device *pdev, /* I - Device info */
fprintf(stderr, "DEBUG: cups->ppd->flip_duplex = %d\n", cups->ppd->flip_duplex);
}
- if (cups->header.Duplex && cups->ppd && cups->ppd->flip_duplex &&
- !(cups->page & 1))
+ if (cups->header.Duplex && !cups->header.Tumble &&
+ cups->ppd && cups->ppd->flip_duplex && !(cups->page & 1))
{
pmat->xx = (float)cups->header.HWResolution[0] / 72.0;
pmat->xy = 0.0;
@@ -1492,6 +1492,7 @@ cups_put_params(gx_device *pdev, /* I - Device info */
gs_param_string stringval; /* String value */
gs_param_float_array arrayval; /* Float array value */
int old_depth; /* Old color depth */
+ int size_set; /* Was the size set? */
gdev_prn_space_params sp; /* Space parameter data */
@@ -1570,6 +1571,7 @@ cups_put_params(gx_device *pdev, /* I - Device info */
}
old_depth = pdev->color_info.depth;
+ size_set = param_read_float_array(plist, "PageSize", &arrayval) == 0;
stringoption(MediaClass, "MediaClass")
stringoption(MediaColor, "MediaColor")
@@ -1701,6 +1703,20 @@ cups_put_params(gx_device *pdev, /* I - Device info */
cups->header.PageSize[0] = pdev->PageSize[0];
cups->header.PageSize[1] = pdev->PageSize[1];
+ /*
+ * Reallocate memory if the size or color depth was changed...
+ */
+
+ if (old_depth != pdev->color_info.depth || size_set)
+ {
+ fputs("DEBUG: Reallocating memory...\n", stderr);
+ sp = ((gx_device_printer *)pdev)->space_params;
+
+ if ((code = gdev_prn_reallocate_memory(pdev, &sp, pdev->width,
+ pdev->height)) < 0)
+ return (code);
+ }
+
#ifdef DEBUG
fprintf(stderr, "DEBUG: ppd = %8x\n", cups->ppd);
fprintf(stderr, "DEBUG: PageSize = [ %.3f %.3f ]\n",
@@ -1974,12 +1990,14 @@ cups_print_chunked(gx_device_printer *pdev, /* I - Printer device */
int flip; /* Flip scanline? */
- if (cups->header.Duplex && cups->ppd && cups->ppd->flip_duplex &&
- !(cups->page & 1))
+ if (cups->header.Duplex && !cups->header.Tumble &&
+ cups->ppd && cups->ppd->flip_duplex && !(cups->page & 1))
flip = 1;
else
flip = 0;
+ fprintf(stderr, "DEBUG: cups_print_chunked - flip = %d\n", flip);
+
/*
* Loop through the page bitmap and write chunked pixels, reversing as
* needed...
@@ -2120,12 +2138,14 @@ cups_print_banded(gx_device_printer *pdev, /* I - Printer device */
int flip; /* Flip scanline? */
- if (cups->header.Duplex && cups->ppd && cups->ppd->flip_duplex &&
- !(cups->page & 1))
+ if (cups->header.Duplex && !cups->header.Tumble &&
+ cups->ppd && cups->ppd->flip_duplex && !(cups->page & 1))
flip = 1;
else
flip = 0;
+ fprintf(stderr, "DEBUG: cups_print_banded - flip = %d\n", flip);
+
/*
* Loop through the page bitmap and write banded pixels... We have
* to separate each chunked color as needed...
@@ -2310,14 +2330,20 @@ cups_print_banded(gx_device_printer *pdev, /* I - Printer device */
x > 0;
x --, srcptr ++)
{
+ /*
+ * Note: Because of the way the pointers are setup,
+ * the following code is correct even though
+ * the names don't match...
+ */
+
if (*srcptr & 0x20)
- *kptr |= bit;
- if (*srcptr & 0x10)
*cptr |= bit;
- if (*srcptr & 0x08)
+ if (*srcptr & 0x10)
*mptr |= bit;
- if (*srcptr & 0x04)
+ if (*srcptr & 0x08)
*yptr |= bit;
+ if (*srcptr & 0x04)
+ *kptr |= bit;
if (*srcptr & 0x02)
*lcptr |= bit;
if (*srcptr & 0x01)
@@ -3035,5 +3061,5 @@ cups_print_planar(gx_device_printer *pdev, /* I - Printer device */
/*
- * End of "$Id: gdevcups.c,v 1.43 2001/03/29 14:58:54 mike Exp $".
+ * End of "$Id: gdevcups.c,v 1.43.2.1 2001/12/26 16:52:48 mike Exp $".
*/
diff --git a/pstoraster/gscrdp.c b/pstoraster/gscrdp.c
index f04803f0cf..c64e703380 100644
--- a/pstoraster/gscrdp.c
+++ b/pstoraster/gscrdp.c
@@ -22,7 +22,7 @@
GNU software to build or run it.
*/
-/*$Id: gscrdp.c,v 1.2 2000/10/13 01:04:41 mike Exp $ */
+/*$Id: gscrdp.c,v 1.2.2.1 2001/12/26 16:52:49 mike Exp $ */
/* CIE color rendering dictionary creation */
#include "math_.h"
#include "memory_.h"
@@ -34,6 +34,7 @@
#include "gscolor2.h" /* for gs_set/currentcolorrendering */
#include "gscrdp.h"
#include "gxarith.h"
+#include "gsmalloc.h"
/* Define the CRD type that we use here. */
#define CRD_TYPE 101
diff --git a/pstoraster/isave.c b/pstoraster/isave.c
index e793af8d7f..f9553b0d5f 100644
--- a/pstoraster/isave.c
+++ b/pstoraster/isave.c
@@ -22,7 +22,7 @@
GNU software to build or run it.
*/
-/*$Id: isave.c,v 1.2 2000/03/08 23:15:15 mike Exp $ */
+/*$Id: isave.c,v 1.2.2.1 2001/12/26 16:52:49 mike Exp $ */
/* Save/restore manager for Ghostscript interpreter */
#include "ghost.h"
#include "memory_.h"
@@ -447,9 +447,11 @@ alloc_save_change(gs_dual_memory_t * dmem, const ref * pcont,
gs_abort();
}
if (r_is_packed(where))
- *(ref_packed *) & cp->contents = *where;
+ *(ref_packed *)(&(cp->contents)) = *where;
else {
- ref_assign_inline(&cp->contents, (ref *) where);
+/* MRS - the following inline assign didn't work...
+ ref_assign_inline(&cp->contents, (ref *) where);*/
+ ref_assign((&(cp->contents)), (ref *) where);
r_set_attrs((ref *) where, l_new);
}
mem->changes = cp;
diff --git a/pstoraster/pstoraster.c b/pstoraster/pstoraster.c
index 5b64b0d152..ea95d5ecab 100644
--- a/pstoraster/pstoraster.c
+++ b/pstoraster/pstoraster.c
@@ -1,5 +1,5 @@
/*
- * "$Id: pstoraster.c,v 1.19 2001/01/24 17:20:05 mike Exp $"
+ * "$Id: pstoraster.c,v 1.19.2.1 2001/12/26 16:52:49 mike Exp $"
*
* PostScript RIP filter main entry for the Common UNIX Printing System
* (CUPS).
@@ -49,6 +49,10 @@
#include
#include
+#ifdef __sgi
+# include
+#endif /* __sgi */
+
#undef bool
#undef uchar
#undef uint
@@ -100,6 +104,16 @@ main(int argc, /* I - Number of command-line arguments */
const char *fontpath; /* CUPS_FONTPATH env variable */
+#ifdef __sgi
+ /*
+ * Force unaligned memory access handling on R12K processors...
+ * (this should be done by default...) Ghostscript is not 64-bit
+ * safe...
+ */
+
+ sysmips(MIPS_FIXADE, 1, 0, 0);
+#endif /* __sgi */
+
/*
* Force the locale to "C" to avoid bugs...
*/
@@ -235,5 +249,5 @@ define_string(const char *name, /* I - Variable to set */
/*
- * End of "$Id: pstoraster.c,v 1.19 2001/01/24 17:20:05 mike Exp $".
+ * End of "$Id: pstoraster.c,v 1.19.2.1 2001/12/26 16:52:49 mike Exp $".
*/
diff --git a/scheduler/Makefile b/scheduler/Makefile
index f335c29ee6..fa47027081 100644
--- a/scheduler/Makefile
+++ b/scheduler/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.36 2001/02/21 17:01:16 mike Exp $"
+# "$Id: Makefile,v 1.36.2.1 2001/12/26 16:52:49 mike Exp $"
#
# Scheduler Makefile for the Common UNIX Printing System (CUPS).
#
@@ -52,25 +52,17 @@ clean:
#
install:
- -$(MKDIR) $(SBINDIR)
- $(CHMOD) ugo+rx $(SBINDIR)
+ $(INSTALL_DIR) $(SBINDIR)
$(INSTALL_BIN) cupsd $(SBINDIR)
- -$(MKDIR) $(SERVERBIN)/daemon
- $(CHMOD) ugo+rx $(SERVERBIN)/daemon
+ $(INSTALL_DIR) $(SERVERBIN)/daemon
$(INSTALL_BIN) cups-lpd $(SERVERBIN)/daemon
$(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon
- -$(MKDIR) $(SERVERROOT)/certs
- $(CHMOD) ugo+x,go-rw $(SERVERROOT)/certs
- -$(MKDIR) $(SERVERROOT)/interfaces
- $(CHMOD) ugo+rx $(SERVERROOT)/interfaces
- -$(MKDIR) $(SERVERROOT)/ppd
- $(CHMOD) ugo+rx $(SERVERROOT)/ppd
- -$(MKDIR) $(LOGDIR)
- $(CHMOD) ugo+rx $(LOGDIR)
- -$(MKDIR) $(REQUESTS)
- $(CHMOD) u+rwx,go-rwx $(REQUESTS)
- -$(MKDIR) $(REQUESTS)/tmp
- $(CHMOD) u+rwx,go-rwx,+t $(REQUESTS)/tmp
+ $(INSTALL_DIR) -m 711 -o $(CUPS_USER) -g $(CUPS_GROUP) $(SERVERROOT)/certs
+ $(INSTALL_DIR) $(SERVERROOT)/interfaces
+ $(INSTALL_DIR) $(SERVERROOT)/ppd
+ $(INSTALL_DIR) $(LOGDIR)
+ $(INSTALL_DIR) -m 700 -o $(CUPS_USER) -g $(CUPS_GROUP) $(REQUESTS)
+ $(INSTALL_DIR) -m 1700 -o $(CUPS_USER) -g $(CUPS_GROUP) $(REQUESTS)/tmp
#
@@ -80,7 +72,7 @@ install:
cupsd: $(CUPSDOBJS) libmime.a ../cups/$(LIBCUPS)
echo Linking $@...
$(CC) $(LDFLAGS) -o cupsd $(CUPSDOBJS) libmime.a \
- $(LIBZ) $(SSLLIBS) $(LIBS) $(LIBMALLOC)
+ $(LIBZ) $(SSLLIBS) $(LIBSLP) $(PAMLIBS) $(LIBS) $(LIBMALLOC)
$(CUPSDOBJS): auth.h banners.h cert.h classes.h client.h conf.h \
cupsd.h dirsvc.h job.h mime.h printers.h \
@@ -149,5 +141,5 @@ $(OBJS): ../config.h ../Makedefs
#
-# End of "$Id: Makefile,v 1.36 2001/02/21 17:01:16 mike Exp $".
+# End of "$Id: Makefile,v 1.36.2.1 2001/12/26 16:52:49 mike Exp $".
#
diff --git a/scheduler/auth.c b/scheduler/auth.c
index fc0e2d809c..e2420b104a 100644
--- a/scheduler/auth.c
+++ b/scheduler/auth.c
@@ -1,5 +1,5 @@
/*
- * "$Id: auth.c,v 1.41.2.2 2001/05/13 18:38:33 mike Exp $"
+ * "$Id: auth.c,v 1.41.2.3 2001/12/26 16:52:50 mike Exp $"
*
* Authorization routines for the Common UNIX Printing System (CUPS).
*
@@ -42,8 +42,11 @@
* IsAuthorized() - Check to see if the user is authorized...
* add_allow() - Add an allow mask to the location.
* add_deny() - Add a deny mask to the location.
+ * cups_crypt() - Encrypt the password using the DES or MD5
+ * algorithms, as needed.
* get_md5_passwd() - Get an MD5 password.
* pam_func() - PAM conversation function.
+ * to64() - Base64-encode an integer value...
*/
/*
@@ -53,6 +56,7 @@
#include "cupsd.h"
#include
#include
+#include
#ifdef HAVE_SHADOW_H
# include
#endif /* HAVE_SHADOW_H */
@@ -73,11 +77,16 @@
static authmask_t *add_allow(location_t *loc);
static authmask_t *add_deny(location_t *loc);
+#if !HAVE_LIBPAM
+static char *cups_crypt(const char *pw, const char *salt);
+#endif /* !HAVE_LIBPAM */
static char *get_md5_passwd(const char *username, const char *group,
char passwd[33]);
#if HAVE_LIBPAM
static int pam_func(int, const struct pam_message **,
struct pam_response **, void *);
+#else
+static void to64(char *s, unsigned long v, int n);
#endif /* HAVE_LIBPAM */
@@ -515,7 +524,8 @@ DenyIP(location_t *loc, /* I - Location to add to */
*/
location_t * /* O - Location that matches */
-FindBest(client_t *con) /* I - Connection */
+FindBest(const char *path, /* I - Resource path */
+ http_state_t state) /* I - HTTP state/request */
{
int i; /* Looping var */
location_t *loc, /* Current location */
@@ -541,11 +551,35 @@ FindBest(client_t *con) /* I - Connection */
};
+ /*
+ * First copy the connection URI to a local string so we have drop
+ * any .ppd extension from the pathname in /printers or /classes
+ * URIs...
+ */
+
+ strncpy(uri, path, sizeof(uri) - 1);
+ uri[sizeof(uri) - 1] = '\0';
+
+ if (strncmp(uri, "/printers/", 10) == 0 ||
+ strncmp(uri, "/classes/", 9) == 0)
+ {
+ /*
+ * Check if the URI has .ppd on the end...
+ */
+
+ uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */
+
+ if (strcmp(uriptr, ".ppd") == 0)
+ *uriptr = '\0';
+ }
+
+ LogMessage(L_DEBUG2, "FindBest: uri = \"%s\"...", uri);
+
/*
* Loop through the list of locations to find a match...
*/
- limit = limits[con->http.state];
+ limit = limits[state];
best = NULL;
bestlen = 0;
@@ -612,7 +646,8 @@ IsAuthorized(client_t *con) /* I - Connection */
struct group *grp; /* Group data */
char nonce[HTTP_MAX_VALUE],
/* Nonce value from client */
- md5[33]; /* MD5 password */
+ md5[33], /* MD5 password */
+ basicmd5[33]; /* MD5 of Basic password */
#if HAVE_LIBPAM
pam_handle_t *pamh; /* PAM authentication handle */
int pamerr; /* PAM error code */
@@ -653,7 +688,7 @@ IsAuthorized(client_t *con) /* I - Connection */
* not authorized...
*/
- if ((best = FindBest(con)) == NULL)
+ if ((best = FindBest(con->uri, con->http.state)) == NULL)
return (HTTP_FORBIDDEN);
/*
@@ -702,6 +737,14 @@ IsAuthorized(client_t *con) /* I - Connection */
auth = AUTH_ALLOW;
}
+ else if (best->num_allow == 0 && best->num_deny == 0)
+ {
+ /*
+ * No allow/deny lines - allow access...
+ */
+
+ auth = AUTH_ALLOW;
+ }
else
{
/*
@@ -795,7 +838,10 @@ IsAuthorized(client_t *con) /* I - Connection */
LogMessage(L_DEBUG2, "IsAuthorized: Checking \"%s\", address = %08x, hostname = \"%s\"",
con->username, address, con->http.hostname);
- if (strcasecmp(con->http.hostname, "localhost") != 0 ||
+ pw = NULL;
+
+ if ((address != 0x7f000001 &&
+ strcasecmp(con->http.hostname, "localhost") != 0) ||
strncmp(con->http.fields[HTTP_FIELD_AUTHORIZATION], "Local", 5) != 0)
{
/*
@@ -806,172 +852,243 @@ IsAuthorized(client_t *con) /* I - Connection */
return (HTTP_UNAUTHORIZED);
/*
- * See if we are doing Digest or Basic authentication...
+ * See what kind of authentication we are doing...
*/
- if (best->type == AUTH_BASIC)
+ switch (best->type)
{
+ case AUTH_BASIC :
+ /*
+ * Get the user info...
+ */
+
+ pw = getpwnam(con->username); /* Get the current password */
+ endpwent(); /* Close the password file */
+
+ if (pw == NULL) /* No such user... */
+ {
+ LogMessage(L_WARN, "IsAuthorized: Unknown username \"%s\"; access denied.",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
+
#if HAVE_LIBPAM
- /*
- * Only use PAM to do authentication. This allows MD5 passwords, among
- * other things...
- */
+ /*
+ * Only use PAM to do authentication. This allows MD5 passwords, among
+ * other things...
+ */
- pamdata.conv = pam_func;
- pamdata.appdata_ptr = con;
+ pamdata.conv = pam_func;
+ pamdata.appdata_ptr = con;
# ifdef __hpux
- /*
- * Workaround for HP-UX bug in pam_unix; see pam_conv() below for
- * more info...
- */
+ /*
+ * Workaround for HP-UX bug in pam_unix; see pam_conv() below for
+ * more info...
+ */
- auth_client = con;
+ auth_client = con;
# endif /* __hpux */
- DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con));
+ DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con));
- pamerr = pam_start("cups", con->username, &pamdata, &pamh);
- if (pamerr != PAM_SUCCESS)
- {
- LogMessage(L_ERROR, "IsAuthorized: pam_start() returned %d (%s)!\n",
- pamerr, pam_strerror(pamh, pamerr));
- pam_end(pamh, 0);
- return (HTTP_UNAUTHORIZED);
- }
-
- pamerr = pam_authenticate(pamh, PAM_SILENT);
- if (pamerr != PAM_SUCCESS)
- {
- LogMessage(L_ERROR, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
- pamerr, pam_strerror(pamh, pamerr));
- pam_end(pamh, 0);
- return (HTTP_UNAUTHORIZED);
- }
-
- pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
- if (pamerr != PAM_SUCCESS)
- {
- LogMessage(L_ERROR, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
- pamerr, pam_strerror(pamh, pamerr));
- pam_end(pamh, 0);
- return (HTTP_UNAUTHORIZED);
- }
+ pamerr = pam_start("cups", con->username, &pamdata, &pamh);
+ if (pamerr != PAM_SUCCESS)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: pam_start() returned %d (%s)!\n",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ pamerr = pam_authenticate(pamh, PAM_SILENT);
+ if (pamerr != PAM_SUCCESS)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
+ if (pamerr != PAM_SUCCESS)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
+ pamerr, pam_strerror(pamh, pamerr));
+ pam_end(pamh, 0);
+ return (HTTP_UNAUTHORIZED);
+ }
- pam_end(pamh, PAM_SUCCESS);
+ pam_end(pamh, PAM_SUCCESS);
#elif defined(HAVE_USERSEC_H)
- /*
- * Use AIX authentication interface...
- */
+ /*
+ * Use AIX authentication interface...
+ */
- LogMessage(L_DEBUG, "IsAuthorized: AIX authenticate of username \"%s\"",
- con->username);
+ LogMessage(L_DEBUG, "IsAuthorized: AIX authenticate of username \"%s\"",
+ con->username);
- reenter = 1;
- if (authenticate(con->username, con->password, &reenter, &authmsg) != 0)
- {
- LogMessage(L_DEBUG, "IsAuthorized: Unable to authenticate username \"%s\": %s",
- con->username, strerror(errno));
- return (HTTP_UNAUTHORIZED);
- }
+ reenter = 1;
+ if (authenticate(con->username, con->password, &reenter, &authmsg) != 0)
+ {
+ LogMessage(L_DEBUG, "IsAuthorized: Unable to authenticate username \"%s\": %s",
+ con->username, strerror(errno));
+ return (HTTP_UNAUTHORIZED);
+ }
#else
# ifdef HAVE_SHADOW_H
- spw = getspnam(con->username);
- endspent();
-
- if (spw == NULL && strcmp(pw->pw_passwd, "x") == 0)
- { /* Don't allow blank passwords! */
- LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
- con->username);
- return (HTTP_UNAUTHORIZED); /* No such user or bad shadow file */
- }
+ spw = getspnam(con->username);
+ endspent();
+
+ if (spw == NULL && strcmp(pw->pw_passwd, "x") == 0)
+ { /* Don't allow blank passwords! */
+ LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
+ con->username);
+ return (HTTP_UNAUTHORIZED); /* No such user or bad shadow file */
+ }
# ifdef DEBUG
- if (spw != NULL)
- printf("spw->sp_pwdp = \"%s\"\n", spw->sp_pwdp);
- else
- puts("spw = NULL");
+ if (spw != NULL)
+ printf("spw->sp_pwdp = \"%s\"\n", spw->sp_pwdp);
+ else
+ puts("spw = NULL");
# endif /* DEBUG */
- if (spw != NULL && spw->sp_pwdp[0] == '\0' && pw->pw_passwd[0] == '\0')
+ if (spw != NULL && spw->sp_pwdp[0] == '\0' && pw->pw_passwd[0] == '\0')
# else
- if (pw->pw_passwd[0] == '\0') /* Don't allow blank passwords! */
+ if (pw->pw_passwd[0] == '\0')
# endif /* HAVE_SHADOW_H */
- { /* Don't allow blank passwords! */
- LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no password; access denied.",
- con->username);
- return (HTTP_UNAUTHORIZED);
- }
+ { /* Don't allow blank passwords! */
+ LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no password; access denied.",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
- /*
- * OK, the password isn't blank, so compare with what came from the client...
- */
+ /*
+ * OK, the password isn't blank, so compare with what came from the client...
+ */
- LogMessage(L_DEBUG2, "IsAuthorized: pw_passwd = %s, crypt = %s",
- pw->pw_passwd, crypt(con->password, pw->pw_passwd));
+ pass = cups_crypt(con->password, pw->pw_passwd);
- pass = crypt(con->password, pw->pw_passwd);
+ LogMessage(L_DEBUG2, "IsAuthorized: pw_passwd = %s, crypt = %s",
+ pw->pw_passwd, pass);
- if (pass == NULL ||
- strcmp(pw->pw_passwd, crypt(con->password, pw->pw_passwd)) != 0)
- {
+ if (pass == NULL || strcmp(pw->pw_passwd, pass) != 0)
+ {
# ifdef HAVE_SHADOW_H
- if (spw != NULL)
- {
- LogMessage(L_DEBUG2, "IsAuthorized: sp_pwdp = %s, crypt = %s",
- spw->sp_pwdp, crypt(con->password, spw->sp_pwdp));
+ if (spw != NULL)
+ {
+ pass = cups_crypt(con->password, spw->sp_pwdp);
- pass = crypt(con->password, spw->sp_pwdp);
+ LogMessage(L_DEBUG2, "IsAuthorized: sp_pwdp = %s, crypt = %s",
+ spw->sp_pwdp, pass);
- if (pass == NULL ||
- strcmp(spw->sp_pwdp, crypt(con->password, spw->sp_pwdp)) != 0)
- return (HTTP_UNAUTHORIZED);
- }
- else
+ if (pass == NULL || strcmp(spw->sp_pwdp, pass) != 0)
+ return (HTTP_UNAUTHORIZED);
+ }
+ else
# endif /* HAVE_SHADOW_H */
- return (HTTP_UNAUTHORIZED);
- }
+ return (HTTP_UNAUTHORIZED);
+ }
#endif /* HAVE_LIBPAM */
- }
- else
- {
- /*
- * Do Digest authentication...
- */
-
- if (!httpGetSubField(&(con->http), HTTP_FIELD_WWW_AUTHENTICATE, "nonce",
- nonce))
- {
- LogMessage(L_ERROR, "IsAuthorized: No nonce value for Digest authentication!");
- return (HTTP_UNAUTHORIZED);
- }
-
- if (strcmp(con->http.hostname, nonce) != 0)
- {
- LogMessage(L_ERROR, "IsAuthorized: Nonce value error!");
- LogMessage(L_ERROR, "IsAuthorized: Expected \"%s\",",
- con->http.hostname);
- LogMessage(L_ERROR, "IsAuthorized: Got \"%s\"!", nonce);
- return (HTTP_UNAUTHORIZED);
- }
+ break;
+ case AUTH_DIGEST :
+ /*
+ * Do Digest authentication...
+ */
- if (!get_md5_passwd(con->username, best->names[0], md5))
- {
- LogMessage(L_ERROR, "IsAuthorized: No user:group for \"%s:%s\" in passwd.md5!",
- con->username, best->names[0]);
- return (HTTP_UNAUTHORIZED);
- }
+ if (!httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "nonce",
+ nonce))
+ {
+ LogMessage(L_ERROR, "IsAuthorized: No nonce value for Digest authentication!");
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ if (strcmp(con->http.hostname, nonce) != 0)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: Nonce value error!");
+ LogMessage(L_ERROR, "IsAuthorized: Expected \"%s\",",
+ con->http.hostname);
+ LogMessage(L_ERROR, "IsAuthorized: Got \"%s\"!", nonce);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ LogMessage(L_DEBUG2, "IsAuthorized: nonce = \"%s\"", nonce);
+
+ if (best->num_names && best->level == AUTH_GROUP)
+ {
+ for (i = 0; i < best->num_names; i ++)
+ if (get_md5_passwd(con->username, best->names[i], md5))
+ break;
+
+ if (i >= best->num_names)
+ md5[0] = '\0';
+ }
+ else if (!get_md5_passwd(con->username, NULL, md5))
+ md5[0] = '\0';
+
+
+ if (!md5[0])
+ {
+ LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ httpMD5Final(nonce, states[con->http.state], con->uri, md5);
+
+ if (strcmp(md5, con->password) != 0)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
+ md5, con->password);
+ return (HTTP_UNAUTHORIZED);
+ }
+ break;
- httpMD5Final(nonce, states[con->http.state], con->uri, md5);
+ case AUTH_BASICDIGEST :
+ /*
+ * Do Basic authentication with the Digest password file...
+ */
- if (strcmp(md5, con->password) != 0)
- {
- LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
- md5, con->password);
- return (HTTP_UNAUTHORIZED);
- }
+ if (best->num_names && best->level == AUTH_GROUP)
+ {
+ for (i = 0; i < best->num_names; i ++)
+ if (get_md5_passwd(con->username, best->names[i], md5))
+ break;
+
+ if (i >= best->num_names)
+ md5[0] = '\0';
+ }
+ else if (!get_md5_passwd(con->username, NULL, md5))
+ md5[0] = '\0';
+
+ if (!md5[0])
+ {
+ LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
+ con->username);
+ return (HTTP_UNAUTHORIZED);
+ }
+
+ httpMD5(con->username, "CUPS", con->password, basicmd5);
+
+ if (strcmp(md5, basicmd5) != 0)
+ {
+ LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
+ md5, basicmd5);
+ return (HTTP_UNAUTHORIZED);
+ }
+ break;
}
}
+ else
+ {
+ /*
+ * Get password entry for certificate-based auth...
+ */
+
+ pw = getpwnam(con->username); /* Get the current password */
+ endpwent(); /* Close the password file */
+ }
/*
* OK, the password is good. See if we need normal user access, or group
@@ -1011,37 +1128,52 @@ IsAuthorized(client_t *con) /* I - Connection */
LogMessage(L_DEBUG2, "IsAuthorized: Checking group membership...");
- for (i = 0; i < best->num_names; i ++)
+ if (best->type == AUTH_BASIC)
{
- grp = getgrnam(best->names[i]);
- endgrent();
+ /*
+ * Check to see if this user is in any of the named groups...
+ */
+
+ LogMessage(L_DEBUG2, "IsAuthorized: Checking group membership...");
- if (grp == NULL) /* No group by that name??? */
+ for (i = 0; i < best->num_names; i ++)
{
- LogMessage(L_WARN, "IsAuthorized: group name \"%s\" does not exist!",
- best->names[i]);
- return (HTTP_FORBIDDEN);
- }
+ grp = getgrnam(best->names[i]);
+ endgrent();
+
+ if (grp == NULL) /* No group by that name??? */
+ {
+ LogMessage(L_WARN, "IsAuthorized: group name \"%s\" does not exist!",
+ best->names[i]);
+ return (HTTP_FORBIDDEN);
+ }
- for (j = 0; grp->gr_mem[j] != NULL; j ++)
- if (strcmp(con->username, grp->gr_mem[j]) == 0)
+ for (j = 0; grp->gr_mem[j] != NULL; j ++)
+ if (strcmp(con->username, grp->gr_mem[j]) == 0)
+ return (HTTP_OK);
+
+ /*
+ * Check to see if the default group ID matches for the user...
+ */
+
+ if (grp->gr_gid == pw->pw_gid)
return (HTTP_OK);
+ }
/*
- * Check to see if the default group ID matches for the user...
+ * The user isn't part of the specified group, so deny access...
*/
- if (grp->gr_gid == pw->pw_gid)
- return (HTTP_OK);
+ LogMessage(L_DEBUG2, "IsAuthorized: user not in group!");
+
+ return (HTTP_UNAUTHORIZED);
}
/*
- * The user isn't part of the specified group, so deny access...
+ * All checks passed...
*/
- LogMessage(L_DEBUG2, "IsAuthorized: user not in group!");
-
- return (HTTP_UNAUTHORIZED);
+ return (HTTP_OK);
}
@@ -1129,6 +1261,129 @@ add_deny(location_t *loc) /* I - Location to add to */
}
+#if !HAVE_LIBPAM
+/*
+ * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
+ * as needed.
+ */
+
+static char * /* O - Encrypted password */
+cups_crypt(const char *pw, /* I - Password string */
+ const char *salt) /* I - Salt (key) string */
+{
+ if (strncmp(salt, "$1$", 3) == 0)
+ {
+ /*
+ * Use MD5 passwords without the benefit of PAM; this is for
+ * Slackware Linux, and the algorithm was taken from the
+ * old shadow-19990827/lib/md5crypt.c source code... :(
+ */
+
+ int i; /* Looping var */
+ unsigned long n; /* Output number */
+ int pwlen; /* Length of password string */
+ const char *salt_end; /* End of "salt" data for MD5 */
+ char *ptr; /* Pointer into result string */
+ md5_state_t state; /* Primary MD5 state info */
+ md5_state_t state2; /* Secondary MD5 state info */
+ md5_byte_t digest[16]; /* MD5 digest result */
+ static char result[120]; /* Final password string */
+
+
+ /*
+ * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
+ * Get a maximum of 8 characters of salt data after $1$...
+ */
+
+ for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
+ if (*salt_end == '$')
+ break;
+
+ /*
+ * Compute the MD5 sum we need...
+ */
+
+ pwlen = strlen(pw);
+
+ md5_init(&state);
+ md5_append(&state, pw, pwlen);
+ md5_append(&state, salt, salt_end - salt);
+
+ md5_init(&state2);
+ md5_append(&state2, pw, pwlen);
+ md5_append(&state2, salt + 3, salt_end - salt - 3);
+ md5_append(&state2, pw, pwlen);
+ md5_finish(&state, digest);
+
+ for (i = pwlen; i > 0; i -= 16)
+ md5_append(&state, digest, i > 16 ? 16 : i);
+
+ for (i = pwlen; i > 0; i >>= 1)
+ md5_append(&state, (i & 1) ? "" : pw, 1);
+
+ md5_finish(&state, digest);
+
+ for (i = 0; i < 1000; i ++)
+ {
+ md5_init(&state);
+
+ if (i & 1)
+ md5_append(&state, pw, pwlen);
+ else
+ md5_append(&state, digest, 16);
+
+ if (i % 3)
+ md5_append(&state, salt + 3, salt_end - salt - 3);
+
+ if (i % 7)
+ md5_append(&state, pw, pwlen);
+
+ if (i & 1)
+ md5_append(&state, digest, 16);
+ else
+ md5_append(&state, pw, pwlen);
+
+ md5_finish(&state, digest);
+ }
+
+ /*
+ * Copy the final sum to the result string and return...
+ */
+
+ memcpy(result, salt, salt_end - salt);
+ ptr = result + (salt_end - salt);
+ *ptr++ = '$';
+
+ for (i = 0; i < 5; i ++, ptr += 4)
+ {
+ n = (((digest[i] << 8) | digest[i + 6]) << 8);
+
+ if (i < 4)
+ n |= digest[i + 12];
+ else
+ n |= digest[5];
+
+ to64(ptr, n, 4);
+ }
+
+ to64(ptr, digest[11], 2);
+ ptr += 2;
+ *ptr = '\0';
+
+ return (result);
+ }
+ else
+ {
+ /*
+ * Use the standard crypt() function...
+ */
+
+ return (crypt(pw, salt));
+ }
+}
+#endif /* !HAVE_LIBPAM */
+
+
/*
* 'get_md5_passwd()' - Get an MD5 password.
*/
@@ -1264,9 +1519,29 @@ pam_func(int num_msg, /* I - Number of messages */
return (PAM_SUCCESS);
}
+#else
+
+
+/*
+ * 'to64()' - Base64-encode an integer value...
+ */
+
+static void
+to64(char *s, /* O - Output string */
+ unsigned long v, /* I - Value to encode */
+ int n) /* I - Number of digits */
+{
+ const char *itoa64 = "./0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz";
+
+
+ for (; n > 0; n --, v >>= 6)
+ *s++ = itoa64[v & 0x3f];
+}
#endif /* HAVE_LIBPAM */
/*
- * End of "$Id: auth.c,v 1.41.2.2 2001/05/13 18:38:33 mike Exp $".
+ * End of "$Id: auth.c,v 1.41.2.3 2001/12/26 16:52:50 mike Exp $".
*/
diff --git a/scheduler/auth.h b/scheduler/auth.h
index cf49207e75..3cdf5884f0 100644
--- a/scheduler/auth.h
+++ b/scheduler/auth.h
@@ -1,5 +1,5 @@
/*
- * "$Id: auth.h,v 1.16.2.1 2001/04/02 19:51:47 mike Exp $"
+ * "$Id: auth.h,v 1.16.2.2 2001/12/26 16:52:50 mike Exp $"
*
* Authorization definitions for the Common UNIX Printing System (CUPS)
* scheduler.
@@ -30,6 +30,7 @@
#define AUTH_NONE 0 /* No authentication */
#define AUTH_BASIC 1 /* Basic authentication */
#define AUTH_DIGEST 2 /* Digest authentication */
+#define AUTH_BASICDIGEST 3 /* Basic authentication w/passwd.md5 */
#define AUTH_ANON 0 /* Anonymous access */
#define AUTH_USER 1 /* Must have a valid username/password */
@@ -125,11 +126,11 @@ extern void DeleteAllLocations(void);
extern void DenyHost(location_t *loc, char *name);
extern void DenyIP(location_t *loc, unsigned address[4],
unsigned netmask[4]);
-extern location_t *FindBest(client_t *con);
+extern location_t *FindBest(client_t *con, http_state_t state);
extern location_t *FindLocation(const char *location);
extern http_status_t IsAuthorized(client_t *con);
/*
- * End of "$Id: auth.h,v 1.16.2.1 2001/04/02 19:51:47 mike Exp $".
+ * End of "$Id: auth.h,v 1.16.2.2 2001/12/26 16:52:50 mike Exp $".
*/
diff --git a/scheduler/banners.c b/scheduler/banners.c
index dfe0b532de..49a74367ee 100644
--- a/scheduler/banners.c
+++ b/scheduler/banners.c
@@ -1,5 +1,5 @@
/*
- * "$Id: banners.c,v 1.5 2001/01/22 15:03:58 mike Exp $"
+ * "$Id: banners.c,v 1.5.2.1 2001/12/26 16:52:50 mike Exp $"
*
* Banner routines for the Common UNIX Printing System (CUPS).
*
@@ -91,7 +91,6 @@ AddBanner(const char *name, /* I - Name of banner */
memset(temp, 0, sizeof(banner_t));
strncpy(temp->name, name, sizeof(temp->name) - 1);
- strncpy(temp->filename, filename, sizeof(temp->filename) - 1);
temp->filetype = filetype;
}
@@ -213,5 +212,5 @@ compare(const banner_t *b0, /* I - First banner */
/*
- * End of "$Id: banners.c,v 1.5 2001/01/22 15:03:58 mike Exp $".
+ * End of "$Id: banners.c,v 1.5.2.1 2001/12/26 16:52:50 mike Exp $".
*/
diff --git a/scheduler/banners.h b/scheduler/banners.h
index c616643ba9..5c7e39949d 100644
--- a/scheduler/banners.h
+++ b/scheduler/banners.h
@@ -1,5 +1,5 @@
/*
- * "$Id: banners.h,v 1.2 2001/01/22 15:03:58 mike Exp $"
+ * "$Id: banners.h,v 1.2.2.1 2001/12/26 16:52:50 mike Exp $"
*
* Banner definitions for the Common UNIX Printing System (CUPS).
*
@@ -29,7 +29,6 @@
typedef struct
{
char name[256]; /* Name of banner */
- char filename[1024]; /* Full filename */
mime_type_t *filetype; /* Filetype for banner */
} banner_t;
@@ -54,5 +53,5 @@ extern void LoadBanners(const char *d);
/*
- * End of "$Id: banners.h,v 1.2 2001/01/22 15:03:58 mike Exp $".
+ * End of "$Id: banners.h,v 1.2.2.1 2001/12/26 16:52:50 mike Exp $".
*/
diff --git a/scheduler/cert.c b/scheduler/cert.c
index 325fb1d813..129a47a3e8 100644
--- a/scheduler/cert.c
+++ b/scheduler/cert.c
@@ -1,5 +1,5 @@
/*
- * "$Id: cert.c,v 1.7.2.1 2001/05/13 18:38:34 mike Exp $"
+ * "$Id: cert.c,v 1.7.2.2 2001/12/26 16:52:50 mike Exp $"
*
* Authentication certificate routines for the Common UNIX
* Printing System (CUPS).
@@ -95,7 +95,7 @@ AddCert(int pid, /* I - Process ID */
fchmod(fileno(fp), 0440);
- if ((grp = getgrnam(SystemGroup)) == NULL)
+ if ((grp = getgrnam(SystemGroups[0])) == NULL)
fchown(fileno(fp), getuid(), 0);
else
fchown(fileno(fp), getuid(), grp->gr_gid);
@@ -271,5 +271,5 @@ InitCerts(void)
/*
- * End of "$Id: cert.c,v 1.7.2.1 2001/05/13 18:38:34 mike Exp $".
+ * End of "$Id: cert.c,v 1.7.2.2 2001/12/26 16:52:50 mike Exp $".
*/
diff --git a/scheduler/classes.c b/scheduler/classes.c
index f18442806d..973072bd5e 100644
--- a/scheduler/classes.c
+++ b/scheduler/classes.c
@@ -1,5 +1,5 @@
/*
- * "$Id: classes.c,v 1.34.2.1 2001/04/02 19:51:47 mike Exp $"
+ * "$Id: classes.c,v 1.34.2.2 2001/12/26 16:52:50 mike Exp $"
*
* Printer class routines for the Common UNIX Printing System (CUPS).
*
@@ -374,12 +374,12 @@ LoadAllClasses(void)
continue;
/*
- * Strip trailing newline, if any...
+ * Strip trailing whitespace, if any...
*/
len = strlen(line);
- if (line[len - 1] == '\n')
+ while (len > 0 && isspace(line[len - 1]))
{
len --;
line[len] = '\0';
@@ -600,8 +600,10 @@ SaveAllClasses(void)
if (pclass->info[0])
fprintf(fp, "Info %s\n", pclass->info);
- if (pclass->more_info[0])
+
+ if (pclass->location[0])
fprintf(fp, "Location %s\n", pclass->location);
+
if (pclass->state == IPP_PRINTER_STOPPED)
{
fputs("State Stopped\n", fp);
@@ -609,6 +611,7 @@ SaveAllClasses(void)
}
else
fputs("State Idle\n", fp);
+
if (pclass->accepting)
fputs("Accepting Yes\n", fp);
else
@@ -617,12 +620,9 @@ SaveAllClasses(void)
for (i = 0; i < pclass->num_printers; i ++)
fprintf(fp, "Printer %s\n", pclass->printers[i]->name);
- if (pclass->quota_period)
- {
- fprintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
- fprintf(fp, "PageLimit %d\n", pclass->page_limit);
- fprintf(fp, "KLimit %d\n", pclass->k_limit);
- }
+ fprintf(fp, "QuotaPeriod %d\n", pclass->quota_period);
+ fprintf(fp, "PageLimit %d\n", pclass->page_limit);
+ fprintf(fp, "KLimit %d\n", pclass->k_limit);
for (i = 0; i < pclass->num_users; i ++)
fprintf(fp, "%sUser %s\n", pclass->deny_users ? "Deny" : "Allow",
@@ -636,5 +636,5 @@ SaveAllClasses(void)
/*
- * End of "$Id: classes.c,v 1.34.2.1 2001/04/02 19:51:47 mike Exp $".
+ * End of "$Id: classes.c,v 1.34.2.2 2001/12/26 16:52:50 mike Exp $".
*/
diff --git a/scheduler/client.c b/scheduler/client.c
index 6fee41f944..dc799158bf 100644
--- a/scheduler/client.c
+++ b/scheduler/client.c
@@ -1,5 +1,5 @@
/*
- * "$Id: client.c,v 1.91.2.3 2001/05/14 18:01:22 mike Exp $"
+ * "$Id: client.c,v 1.91.2.4 2001/12/26 16:52:50 mike Exp $"
*
* Client routines for the Common UNIX Printing System (CUPS) scheduler.
*
@@ -36,6 +36,7 @@
* check_if_modified() - Decode an "If-Modified-Since" line.
* decode_auth() - Decode an authorization string.
* get_file() - Get a filename and state info.
+ * install_conf_file() - Install a configuration file.
* pipe_command() - Pipe the output of a command to the remote client.
*/
@@ -58,10 +59,13 @@
* Local functions...
*/
-static int check_if_modified(client_t *con, struct stat *filestats);
-static void decode_auth(client_t *con);
-static char *get_file(client_t *con, struct stat *filestats);
-static int pipe_command(client_t *con, int infile, int *outfile, char *command, char *options);
+static int check_if_modified(client_t *con,
+ struct stat *filestats);
+static void decode_auth(client_t *con);
+static char *get_file(client_t *con, struct stat *filestats);
+static http_status_t install_conf_file(client_t *con);
+static int pipe_command(client_t *con, int infile, int *outfile,
+ char *command, char *options);
/*
@@ -160,7 +164,7 @@ AcceptClient(listener_t *lis) /* I - Listener socket */
* Do double lookups as needed...
*/
- if ((host = gethostbyname(con->http.hostname)) != NULL)
+ if ((host = httpGetHostByName(con->http.hostname)) != NULL)
{
/*
* See if the hostname maps to the same IP address...
@@ -393,7 +397,7 @@ EncryptClient(client_t *con) /* I - Client to encrypt */
#ifdef HAVE_LIBSSL
SSL_CTX *context; /* Context for encryption */
SSL *conn; /* Connection for encryption */
- int error; /* Error code */
+ unsigned long error; /* Error code */
/*
@@ -432,7 +436,7 @@ EncryptClient(client_t *con) /* I - Client to encrypt */
int /* O - 1 on success, 0 on error */
ReadClient(client_t *con) /* I - Client to read from */
{
- char line[8192], /* Line from client... */
+ char line[32768], /* Line from client... */
operation[64], /* Operation code from socket */
version[64]; /* HTTP version number string */
int major, minor; /* HTTP version numbers */
@@ -519,7 +523,7 @@ ReadClient(client_t *con) /* I - Client to read from */
if (major < 2)
{
con->http.version = (http_version_t)(major * 100 + minor);
- if (con->http.version == HTTP_1_1)
+ if (con->http.version == HTTP_1_1 && KeepAlive)
con->http.keep_alive = HTTP_KEEPALIVE_ON;
else
con->http.keep_alive = HTTP_KEEPALIVE_OFF;
@@ -602,7 +606,8 @@ ReadClient(client_t *con) /* I - Client to read from */
decode_auth(con);
- if (strncmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", 10) == 0)
+ if (strncmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", 10) == 0 &&
+ KeepAlive)
con->http.keep_alive = HTTP_KEEPALIVE_ON;
if (con->http.fields[HTTP_FIELD_HOST][0] == '\0' &&
@@ -624,7 +629,7 @@ ReadClient(client_t *con) /* I - Client to read from */
* Do OPTIONS command...
*/
- if ((best = FindBest(con)) != NULL &&
+ if ((best = FindBest(con->uri, con->http.state)) != NULL &&
best->type != AUTH_NONE)
{
if (!SendHeader(con, HTTP_UNAUTHORIZED, NULL))
@@ -669,7 +674,7 @@ ReadClient(client_t *con) /* I - Client to read from */
return (0);
}
- httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST\r\n");
+ httpPrintf(HTTP(con), "Allow: GET, HEAD, OPTIONS, POST, PUT\r\n");
httpPrintf(HTTP(con), "Content-Length: 0\r\n");
httpPrintf(HTTP(con), "\r\n");
}
@@ -764,7 +769,8 @@ ReadClient(client_t *con) /* I - Client to read from */
}
}
- if (strncmp(con->uri, "/admin", 6) == 0 ||
+ if ((strncmp(con->uri, "/admin", 6) == 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0) ||
strncmp(con->uri, "/printers", 9) == 0 ||
strncmp(con->uri, "/classes", 8) == 0 ||
strncmp(con->uri, "/jobs", 5) == 0)
@@ -815,6 +821,23 @@ ReadClient(client_t *con) /* I - Client to read from */
if (con->http.version <= HTTP_1_0)
con->http.keep_alive = HTTP_KEEPALIVE_OFF;
}
+ else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
+ (strchr(con->uri + 12, '/') != NULL ||
+ strlen(con->uri) == 12))
+ {
+ /*
+ * GET can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ if (!SendError(con, HTTP_FORBIDDEN))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
else
{
/*
@@ -887,7 +910,8 @@ ReadClient(client_t *con) /* I - Client to read from */
if (strcmp(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "application/ipp") == 0)
con->request = ippNew();
- else if (strncmp(con->uri, "/admin", 6) == 0 ||
+ else if ((strncmp(con->uri, "/admin", 6) == 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0) ||
strncmp(con->uri, "/printers", 9) == 0 ||
strncmp(con->uri, "/classes", 8) == 0 ||
strncmp(con->uri, "/jobs", 5) == 0)
@@ -938,6 +962,76 @@ ReadClient(client_t *con) /* I - Client to read from */
break;
case HTTP_PUT_RECV :
+ /*
+ * Validate the resource name...
+ */
+
+ if (strncmp(con->uri, "/admin/conf/", 12) != 0 ||
+ strchr(con->uri + 12, '/') != NULL ||
+ strlen(con->uri) == 12)
+ {
+ /*
+ * PUT can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ if (!SendError(con, HTTP_FORBIDDEN))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+
+ /*
+ * See if the PUT request includes a Content-Length field, and if
+ * so check the length against any limits that are set...
+ */
+
+ LogMessage(L_DEBUG2, "PUT %s", con->uri);
+ LogMessage(L_DEBUG2, "CONTENT_TYPE = %s", con->http.fields[HTTP_FIELD_CONTENT_TYPE]);
+
+ if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
+ atoi(con->http.fields[HTTP_FIELD_CONTENT_LENGTH]) > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request too large...
+ */
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
+
+ /*
+ * Open a temporary file to hold the request...
+ */
+
+ snprintf(con->filename, sizeof(con->filename), "%s/%08x",
+ RequestRoot, request_id ++);
+ con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640);
+ fchmod(con->file, 0640);
+ fchown(con->file, User, Group);
+
+ LogMessage(L_DEBUG2, "ReadClient() %d REQUEST %s=%d", con->http.fd,
+ con->filename, con->file);
+
+ if (con->file < 0)
+ {
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ break;
+
case HTTP_DELETE :
case HTTP_TRACE :
SendError(con, HTTP_NOT_IMPLEMENTED);
@@ -969,7 +1063,8 @@ ReadClient(client_t *con) /* I - Client to read from */
}
}
- if (strncmp(con->uri, "/admin/", 7) == 0 ||
+ if ((strncmp(con->uri, "/admin/", 7) == 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0) ||
strncmp(con->uri, "/printers/", 10) == 0 ||
strncmp(con->uri, "/classes/", 9) == 0 ||
strncmp(con->uri, "/jobs/", 6) == 0)
@@ -992,6 +1087,23 @@ ReadClient(client_t *con) /* I - Client to read from */
LogRequest(con, HTTP_OK);
}
+ else if (strncmp(con->uri, "/admin/conf/", 12) == 0 &&
+ (strchr(con->uri + 12, '/') != NULL ||
+ strlen(con->uri) == 12))
+ {
+ /*
+ * HEAD can only be done to configuration files under
+ * /admin/conf...
+ */
+
+ if (!SendError(con, HTTP_FORBIDDEN))
+ {
+ CloseClient(con);
+ return (0);
+ }
+
+ break;
+ }
else if ((filename = get_file(con, &filestats)) == NULL)
{
if (!SendHeader(con, HTTP_NOT_FOUND, "text/html"))
@@ -1037,8 +1149,8 @@ ReadClient(client_t *con) /* I - Client to read from */
return (0);
}
- if (httpPrintf(HTTP(con), "Content-Length: %d\r\n",
- filestats.st_size) < 0)
+ if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
+ (unsigned long)filestats.st_size) < 0)
{
CloseClient(con);
return (0);
@@ -1069,6 +1181,90 @@ ReadClient(client_t *con) /* I - Client to read from */
switch (con->http.state)
{
case HTTP_PUT_RECV :
+ LogMessage(L_DEBUG2, "ReadClient() %d con->data_encoding = %s, con->data_remaining = %d, con->file = %d",
+ con->http.fd,
+ con->http.data_encoding == HTTP_ENCODE_CHUNKED ? "chunked" : "length",
+ con->http.data_remaining, con->file);
+
+ if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0)
+ {
+ CloseClient(con);
+ return (0);
+ }
+ else if (bytes > 0)
+ {
+ con->bytes += bytes;
+
+ LogMessage(L_DEBUG2, "ReadClient() %d writing %d bytes to %d",
+ con->http.fd, bytes, con->file);
+
+ if (write(con->file, line, bytes) < bytes)
+ {
+ LogMessage(L_ERROR, "ReadClient: Unable to write %d bytes to %s: %s",
+ bytes, con->filename, strerror(errno));
+
+ close(con->file);
+ con->file = 0;
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+ }
+
+ if (con->http.state == HTTP_WAITING)
+ {
+ /*
+ * End of file, see how big it is...
+ */
+
+ fstat(con->file, &filestats);
+
+ LogMessage(L_DEBUG2, "ReadClient() %d Closing data file %d, size = %d.",
+ con->http.fd, con->file, filestats.st_size);
+
+ close(con->file);
+ con->file = 0;
+
+ if (filestats.st_size > MaxRequestSize &&
+ MaxRequestSize > 0)
+ {
+ /*
+ * Request is too big; remove it and send an error...
+ */
+
+ LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
+ con->http.fd, con->filename);
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
+
+ /*
+ * Install the configuration file...
+ */
+
+ status = install_conf_file(con);
+
+ /*
+ * Return the status to the client...
+ */
+
+ if (!SendError(con, status))
+ {
+ CloseClient(con);
+ return (0);
+ }
+ }
break;
case HTTP_POST_RECV :
@@ -1143,6 +1339,7 @@ ReadClient(client_t *con) /* I - Client to read from */
close(con->file);
con->file = 0;
unlink(con->filename);
+ con->filename[0] = '\0';
if (!SendError(con, HTTP_REQUEST_TOO_LARGE))
{
@@ -1180,6 +1377,7 @@ ReadClient(client_t *con) /* I - Client to read from */
LogMessage(L_DEBUG2, "ReadClient() %d Removing temp file %s",
con->http.fd, con->filename);
unlink(con->filename);
+ con->filename[0] = '\0';
if (con->request)
{
@@ -1305,7 +1503,7 @@ SendError(client_t *con, /* I - Connection */
if (con->operation > HTTP_WAITING)
LogRequest(con, code);
- LogMessage(L_DEBUG2, "SendError() %d code=%d", con->http.fd, code);
+ LogMessage(L_DEBUG, "SendError() %d code=%d", con->http.fd, code);
/*
* To work around bugs in some proxies, don't use Keep-Alive for some
@@ -1396,7 +1594,8 @@ SendFile(client_t *con,
if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", httpGetDateString(filestats->st_mtime)) < 0)
return (0);
- if (httpPrintf(HTTP(con), "Content-Length: %d\r\n", filestats->st_size) < 0)
+ if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n",
+ (unsigned long)filestats->st_size) < 0)
return (0);
if (httpPrintf(HTTP(con), "\r\n") < 0)
return (0);
@@ -1441,9 +1640,13 @@ SendHeader(client_t *con, /* I - Client to send to */
if (code == HTTP_UNAUTHORIZED)
{
- loc = FindBest(con); /* This already succeeded in IsAuthorized */
+ /*
+ * This already succeeded in IsAuthorized...
+ */
+
+ loc = FindBest(con->uri, con->http.state);
- if (loc->type == AUTH_BASIC)
+ if (loc->type != AUTH_DIGEST)
{
if (httpPrintf(HTTP(con), "WWW-Authenticate: Basic realm=\"CUPS\"\r\n") < 0)
return (0);
@@ -1609,6 +1812,7 @@ WriteClient(client_t *con) /* I - Client connection */
LogMessage(L_DEBUG2, "WriteClient() %d Removing temp file %s",
con->http.fd, con->filename);
unlink(con->filename);
+ con->filename[0] = '\0';
}
if (con->request != NULL)
@@ -1797,6 +2001,8 @@ get_file(client_t *con, /* I - Client connection */
if (strncmp(con->uri, "/ppd/", 5) == 0)
snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri);
+ else if (strncmp(con->uri, "/admin/conf/", 12) == 0)
+ snprintf(filename, sizeof(filename), "%s%s", ServerRoot, con->uri + 11);
else if (con->language != NULL)
snprintf(filename, sizeof(filename), "%s/%s%s", DocumentRoot, con->language->language,
con->uri);
@@ -1817,7 +2023,8 @@ get_file(client_t *con, /* I - Client connection */
* Drop the language prefix and try the current directory...
*/
- if (strncmp(con->uri, "/ppd/", 5) != 0)
+ if (strncmp(con->uri, "/ppd/", 5) != 0 &&
+ strncmp(con->uri, "/admin/conf/", 12) != 0)
{
snprintf(filename, sizeof(filename), "%s%s", DocumentRoot, con->uri);
@@ -1851,6 +2058,160 @@ get_file(client_t *con, /* I - Client connection */
}
+/*
+ * 'install_conf_file()' - Install a configuration file.
+ */
+
+static http_status_t /* O - Status */
+install_conf_file(client_t *con) /* I - Connection */
+{
+ FILE *in, /* Input file */
+ *out; /* Output file */
+ char buffer[1024]; /* Copy buffer */
+ int bytes; /* Number of bytes */
+ char conffile[1024], /* Configuration filename */
+ newfile[1024], /* New config filename */
+ oldfile[1024]; /* Old config filename */
+ struct stat confinfo; /* Config file info */
+
+
+ /*
+ * First construct the filenames...
+ */
+
+ snprintf(conffile, sizeof(conffile), "%s%s", ServerRoot, con->uri + 11);
+ snprintf(newfile, sizeof(newfile), "%s%s.N", ServerRoot, con->uri + 11);
+ snprintf(oldfile, sizeof(oldfile), "%s%s.O", ServerRoot, con->uri + 11);
+
+ LogMessage(L_INFO, "Installing config file \"%s\"...", conffile);
+
+ /*
+ * Get the owner, group, and permissions of the configuration file.
+ * If it doesn't exist, assign it to the User and Group in the
+ * cupsd.conf file with mode 0640 permissions.
+ */
+
+ if (stat(conffile, &confinfo))
+ {
+ confinfo.st_uid = User;
+ confinfo.st_gid = Group;
+ confinfo.st_mode = 0640;
+ }
+
+ /*
+ * Open the request file and new config file...
+ */
+
+ if ((in = fopen(con->filename, "rb")) == NULL)
+ {
+ LogMessage(L_ERROR, "Unable to open request file \"%s\" - %s",
+ con->filename, strerror(errno));
+ return (HTTP_SERVER_ERROR);
+ }
+
+ if ((out = fopen(newfile, "wb")) == NULL)
+ {
+ fclose(in);
+ LogMessage(L_ERROR, "Unable to open config file \"%s\" - %s",
+ newfile, strerror(errno));
+ return (HTTP_SERVER_ERROR);
+ }
+
+ fchmod(fileno(out), confinfo.st_mode);
+ fchown(fileno(out), confinfo.st_uid, confinfo.st_gid);
+
+ /*
+ * Copy from the request to the new config file...
+ */
+
+ while ((bytes = fread(buffer, 1, sizeof(buffer), in)) > 0)
+ if (fwrite(buffer, 1, bytes, out) < bytes)
+ {
+ LogMessage(L_ERROR, "Unable to copy to config file \"%s\" - %s",
+ newfile, strerror(errno));
+
+ fclose(in);
+ fclose(out);
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * Close the files...
+ */
+
+ fclose(in);
+ if (fclose(out))
+ {
+ LogMessage(L_ERROR, "Error file closing config file \"%s\" - %s",
+ newfile, strerror(errno));
+
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * Remove the request file...
+ */
+
+ unlink(con->filename);
+ con->filename[0] = '\0';
+
+ /*
+ * Unlink the old backup, rename the current config file to the backup
+ * filename, and rename the new config file to the config file name...
+ */
+
+ if (unlink(oldfile))
+ if (errno != ENOENT)
+ {
+ LogMessage(L_ERROR, "Unable to remove backup config file \"%s\" - %s",
+ oldfile, strerror(errno));
+
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ if (rename(conffile, oldfile))
+ if (errno != ENOENT)
+ {
+ LogMessage(L_ERROR, "Unable to rename old config file \"%s\" - %s",
+ conffile, strerror(errno));
+
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ if (rename(newfile, conffile))
+ {
+ LogMessage(L_ERROR, "Unable to rename new config file \"%s\" - %s",
+ newfile, strerror(errno));
+
+ rename(oldfile, conffile);
+ unlink(newfile);
+
+ return (HTTP_SERVER_ERROR);
+ }
+
+ /*
+ * If the cupsd.conf file was updated, set the NeedReload flag...
+ */
+
+ if (strcmp(con->uri, "/admin/conf/cupsd.conf") == 0)
+ NeedReload = TRUE;
+
+ /*
+ * Return that the file was created successfully...
+ */
+
+ return (HTTP_CREATED);
+}
+
+
/*
* 'pipe_command()' - Pipe the output of a command to the remote client.
*/
@@ -2051,7 +2412,7 @@ pipe_command(client_t *con, /* I - Client connection */
if (getuid() == 0)
{
/*
- * Running as root, so change to non-priviledged user...
+ * Running as root, so change to a non-priviledged user...
*/
if (setgid(Group))
@@ -2074,11 +2435,13 @@ pipe_command(client_t *con, /* I - Client connection */
if (infile)
{
close(0);
- dup(infile);
+ if (dup(infile) < 0)
+ exit(errno);
}
close(1);
- dup(fds[1]);
+ if (dup(fds[1]) < 0)
+ exit(errno);
/*
* Close extra file descriptors...
@@ -2098,7 +2461,6 @@ pipe_command(client_t *con, /* I - Client connection */
*/
execve(command, argv, envp);
- perror("execve failed");
exit(errno);
return (0);
}
@@ -2123,7 +2485,7 @@ pipe_command(client_t *con, /* I - Client connection */
AddCert(pid, con->username);
- LogMessage(L_DEBUG, "CGI %s started - PID = %d", argv[0], pid);
+ LogMessage(L_DEBUG, "CGI %s started - PID = %d", command, pid);
*outfile = fds[0];
close(fds[1]);
@@ -2134,5 +2496,5 @@ pipe_command(client_t *con, /* I - Client connection */
/*
- * End of "$Id: client.c,v 1.91.2.3 2001/05/14 18:01:22 mike Exp $".
+ * End of "$Id: client.c,v 1.91.2.4 2001/12/26 16:52:50 mike Exp $".
*/
diff --git a/scheduler/conf.c b/scheduler/conf.c
index c0fceaddc0..6da9c3b7fa 100644
--- a/scheduler/conf.c
+++ b/scheduler/conf.c
@@ -1,5 +1,5 @@
/*
- * "$Id: conf.c,v 1.77.2.1 2001/04/02 19:51:48 mike Exp $"
+ * "$Id: conf.c,v 1.77.2.2 2001/12/26 16:52:51 mike Exp $"
*
* Configuration routines for the Common UNIX Printing System (CUPS).
*
@@ -85,6 +85,7 @@ static var_t variables[] =
{ "BrowseTimeout", &BrowseTimeout, VAR_INTEGER, 0 },
{ "Browsing", &Browsing, VAR_BOOLEAN, 0 },
{ "Classification", Classification, VAR_STRING, sizeof(Classification) },
+ { "ClassifyOverride", &ClassifyOverride, VAR_BOOLEAN, 0 },
{ "DataDir", DataDir, VAR_STRING, sizeof(DataDir) },
{ "DefaultCharset", DefaultCharset, VAR_STRING, sizeof(DefaultCharset) },
{ "DefaultLanguage", DefaultLanguage, VAR_STRING, sizeof(DefaultLanguage) },
@@ -92,7 +93,9 @@ static var_t variables[] =
{ "ErrorLog", ErrorLog, VAR_STRING, sizeof(ErrorLog) },
{ "FilterLimit", &FilterLimit, VAR_INTEGER, 0 },
{ "FontPath", FontPath, VAR_STRING, sizeof(FontPath) },
+ { "HideImplicitMembers", &HideImplicitMembers, VAR_BOOLEAN, 0 },
{ "ImplicitClasses", &ImplicitClasses, VAR_BOOLEAN, 0 },
+ { "ImplicitAnyClasses", &ImplicitAnyClasses, VAR_BOOLEAN, 0 },
{ "KeepAliveTimeout", &KeepAliveTimeout, VAR_INTEGER, 0 },
{ "KeepAlive", &KeepAlive, VAR_BOOLEAN, 0 },
{ "LimitRequestBody", &MaxRequestSize, VAR_INTEGER, 0 },
@@ -120,7 +123,6 @@ static var_t variables[] =
#endif /* HAVE_LIBSSL */
{ "ServerName", ServerName, VAR_STRING, sizeof(ServerName) },
{ "ServerRoot", ServerRoot, VAR_STRING, sizeof(ServerRoot) },
- { "SystemGroup", SystemGroup, VAR_STRING, sizeof(SystemGroup) },
{ "TempDir", TempDir, VAR_STRING, sizeof(TempDir) },
{ "Timeout", &Timeout, VAR_INTEGER, 0 }
};
@@ -158,7 +160,10 @@ ReadConfiguration(void)
int i; /* Looping var */
FILE *fp; /* Configuration file */
int status; /* Return status */
- char directory[1024];/* Configuration directory */
+ char directory[1024],/* Configuration directory */
+ *slash; /* Directory separator */
+ char type[MIME_MAX_SUPER + MIME_MAX_TYPE];
+ /* MIME type name */
struct rlimit limit; /* Runtime limit */
char *language; /* Language string */
struct passwd *user; /* Default user */
@@ -196,6 +201,14 @@ ReadConfiguration(void)
if (MimeDatabase != NULL)
mimeDelete(MimeDatabase);
+ if (NumMimeTypes)
+ {
+ for (i = 0; i < NumMimeTypes; i ++)
+ free((void *)MimeTypes[i]);
+
+ free(MimeTypes);
+ }
+
for (i = 0; i < NumRelays; i ++)
if (Relays[i].from.type == AUTH_NAME)
free(Relays[i].from.mask.name.name);
@@ -214,7 +227,6 @@ ReadConfiguration(void)
gethostname(ServerName, sizeof(ServerName));
snprintf(ServerAdmin, sizeof(ServerAdmin), "root@%s", ServerName);
- strcpy(ServerRoot, CUPS_SERVERROOT);
strcpy(ServerBin, CUPS_SERVERBIN);
strcpy(RequestRoot, CUPS_REQUESTS);
strcpy(DocumentRoot, CUPS_DOCROOT);
@@ -226,7 +238,12 @@ ReadConfiguration(void)
strcpy(FontPath, CUPS_FONTPATH);
strcpy(RemoteRoot, "remroot");
+ strcpy(ServerRoot, ConfigurationFile);
+ if ((slash = strrchr(ServerRoot, '/')) != NULL)
+ *slash = '\0';
+
Classification[0] = '\0';
+ ClassifyOverride = 0;
#ifdef HAVE_LIBSSL
strcpy(ServerCertificate, "ssl/server.crt");
@@ -257,39 +274,30 @@ ReadConfiguration(void)
* Find the default system group: "sys", "system", or "root"...
*/
- group = getgrnam("sys");
+ group = getgrnam(CUPS_DEFAULT_GROUP);
endgrent();
+ NumSystemGroups = 0;
+
if (group != NULL)
{
- strcpy(SystemGroup, "sys");
+ strcpy(SystemGroups[0], CUPS_DEFAULT_GROUP);
Group = group->gr_gid;
}
else
{
- group = getgrnam("system");
+ group = getgrgid(0);
endgrent();
if (group != NULL)
{
- strcpy(SystemGroup, "system");
- Group = group->gr_gid;
+ strcpy(SystemGroups[0], group->gr_name);
+ Group = 0;
}
else
{
- group = getgrnam("root");
- endgrent();
-
- if (group != NULL)
- {
- strcpy(SystemGroup, "root");
- Group = group->gr_gid;
- }
- else
- {
- strcpy(SystemGroup, "unknown");
- Group = 0;
- }
+ strcpy(SystemGroups[0], "unknown");
+ Group = 0;
}
}
@@ -297,7 +305,7 @@ ReadConfiguration(void)
* Find the default user...
*/
- if ((user = getpwnam("lp")) == NULL)
+ if ((user = getpwnam(CUPS_DEFAULT_USER)) == NULL)
User = 1; /* Force to a non-priviledged account */
else
User = user->pw_uid;
@@ -412,14 +420,56 @@ ReadConfiguration(void)
ServerCertificate[sizeof(ServerCertificate) - 1] = '\0';
}
+ chown(ServerCertificate, User, Group);
+ chmod(ServerCertificate, 0600);
+
if (ServerKey[0] != '/')
{
snprintf(directory, sizeof(directory), "%s/%s", ServerRoot, ServerKey);
strncpy(ServerKey, directory, sizeof(ServerKey) - 1);
ServerKey[sizeof(ServerKey) - 1] = '\0';
}
+
+ chown(ServerKey, User, Group);
+ chmod(ServerKey, 0600);
#endif /* HAVE_LIBSSL */
+ /*
+ * Make sure that ServerRoot and the config files are owned and
+ * writable by the user and group in the cupsd.conf file...
+ */
+
+ chown(ServerRoot, User, Group);
+ chmod(ServerRoot, 0755);
+
+ snprintf(directory, sizeof(directory), "%s/certs", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0711);
+
+ snprintf(directory, sizeof(directory), "%s/ppd", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0755);
+
+ snprintf(directory, sizeof(directory), "%s/ssl", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0700);
+
+ snprintf(directory, sizeof(directory), "%s/cupsd.conf", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
+ snprintf(directory, sizeof(directory), "%s/classes.conf", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
+ snprintf(directory, sizeof(directory), "%s/printers.conf", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
+ snprintf(directory, sizeof(directory), "%s/passwd.md5", ServerRoot);
+ chown(directory, User, Group);
+ chmod(directory, 0600);
+
/*
* Make sure the request and temporary directories have the right
* permissions...
@@ -445,7 +495,7 @@ ReadConfiguration(void)
getrlimit(RLIMIT_NOFILE, &limit);
- if (MaxClients > (limit.rlim_max / 3))
+ if (MaxClients > (limit.rlim_max / 3) || MaxClients <= 0)
MaxClients = limit.rlim_max / 3;
if ((Clients = calloc(sizeof(client_t), MaxClients)) == NULL)
@@ -465,6 +515,12 @@ ReadConfiguration(void)
if (MaxActiveJobs > (limit.rlim_max / 3))
MaxActiveJobs = limit.rlim_max / 3;
+ if (strcasecmp(Classification, "none") == 0)
+ Classification[0] = '\0';
+
+ if (Classification[0])
+ LogMessage(L_INFO, "Security set to \"%s\"", Classification);
+
/*
* Read the MIME type and conversion database...
*/
@@ -472,6 +528,28 @@ ReadConfiguration(void)
MimeDatabase = mimeNew();
mimeMerge(MimeDatabase, ServerRoot);
+ /*
+ * Create a list of MIME types for the document-format-supported
+ * attribute...
+ */
+
+ NumMimeTypes = MimeDatabase->num_types;
+ if (!mimeType(MimeDatabase, "application", "octet-stream"))
+ NumMimeTypes ++;
+
+ MimeTypes = calloc(NumMimeTypes, sizeof(const char *));
+
+ for (i = 0; i < MimeDatabase->num_types; i ++)
+ {
+ snprintf(type, sizeof(type), "%s/%s", MimeDatabase->types[i]->super,
+ MimeDatabase->types[i]->type);
+
+ MimeTypes[i] = strdup(type);
+ }
+
+ if (i < NumMimeTypes)
+ MimeTypes[i] = strdup("application/octet-stream");
+
/*
* Load banners...
*/
@@ -526,6 +604,7 @@ read_configuration(FILE *fp) /* I - File to read from */
name[256], /* Parameter name */
*nameptr, /* Pointer into name */
*value; /* Pointer to value */
+ int valuelen; /* Length of value */
var_t *var; /* Current variable */
unsigned ip[4], /* Address value */
mask[4]; /* Netmask value */
@@ -533,6 +612,15 @@ read_configuration(FILE *fp) /* I - File to read from */
dirsvc_poll_t *poll; /* Polling data */
http_addr_t polladdr; /* Polling address */
location_t *location; /* Browse location */
+ FILE *incfile; /* Include file */
+ char incname[1024]; /* Include filename */
+ static unsigned netmasks[4] = /* Standard netmasks... */
+ {
+ 0xff000000,
+ 0xffff0000,
+ 0xffffff00,
+ 0xffffffff
+ };
/*
@@ -553,12 +641,12 @@ read_configuration(FILE *fp) /* I - File to read from */
continue;
/*
- * Strip trailing newline, if any...
+ * Strip trailing whitespace, if any...
*/
len = strlen(line);
- if (line[len - 1] == '\n')
+ while (len > 0 && isspace(line[len - 1]))
{
len --;
line[len] = '\0';
@@ -585,7 +673,30 @@ read_configuration(FILE *fp) /* I - File to read from */
* Decode the directive...
*/
- if (strcasecmp(name, "
@@ -726,6 +837,46 @@ read_configuration(FILE *fp) /* I - File to read from */
LogMessage(L_ERROR, "Unknown BrowseOrder value %s on line %d.",
value, linenum);
}
+ else if (strcasecmp(name, "BrowseProtocols") == 0)
+ {
+ /*
+ * "BrowseProtocol name [... name]"
+ */
+
+ BrowseProtocols = 0;
+
+ for (; *value;)
+ {
+ for (valuelen = 0; value[valuelen]; valuelen ++)
+ if (isspace(value[valuelen]) || value[valuelen] == ',')
+ break;
+
+ if (value[valuelen])
+ {
+ value[valuelen] = '\0';
+ valuelen ++;
+ }
+
+ if (strcasecmp(value, "cups") == 0)
+ BrowseProtocols |= BROWSE_CUPS;
+ else if (strcasecmp(value, "slp") == 0)
+ BrowseProtocols |= BROWSE_SLP;
+ else if (strcasecmp(value, "ldap") == 0)
+ BrowseProtocols |= BROWSE_LDAP;
+ else if (strcasecmp(value, "all") == 0)
+ BrowseProtocols |= BROWSE_ALL;
+ else
+ {
+ LogMessage(L_ERROR, "Unknown browse protocol \"%s\" on line %d.",
+ value, linenum);
+ break;
+ }
+
+ for (value += valuelen; *value; value ++)
+ if (!isspace(*value) || *value != ',')
+ break;
+ }
+ }
else if (strcasecmp(name, "BrowseAllow") == 0 ||
strcasecmp(name, "BrowseDeny") == 0)
{
@@ -1048,6 +1199,34 @@ read_configuration(FILE *fp) /* I - File to read from */
value);
}
}
+ else if (strcasecmp(name, "SystemGroup") == 0)
+ {
+ /*
+ * System (admin) group(s)...
+ */
+
+ char *valueptr; /* Pointer into value */
+
+
+ for (i = 0; i < MAX_SYSTEM_GROUPS; i ++)
+ {
+ for (valueptr = value; *valueptr; valueptr ++)
+ if (isspace(*valueptr) || *valueptr == ',')
+ break;
+
+ if (*valueptr)
+ *valueptr++ = '\0';
+
+ strncpy(SystemGroups[i], value, sizeof(SystemGroups[0]));
+ SystemGroups[i][sizeof(SystemGroups[0]) - 1] = '\0';
+
+ while (*value == ',' || isspace(*value))
+ value ++;
+ }
+
+ if (i)
+ NumSystemGroups = i;
+ }
else if (strcasecmp(name, "HostNameLookups") == 0)
{
/*
@@ -1131,7 +1310,31 @@ read_configuration(FILE *fp) /* I - File to read from */
switch (var->type)
{
case VAR_INTEGER :
- *((int *)var->ptr) = atoi(value);
+ {
+ float n; /* Number */
+ char units[255]; /* Units */
+
+
+ switch (sscanf(value, "%f%254s", &n, units))
+ {
+ case 0 :
+ n = 0.0;
+ case 1 :
+ break;
+ case 2 :
+ if (tolower(units[0]) == 'g')
+ n *= 1024.0 * 1024.0 * 1024.0;
+ else if (tolower(units[0]) == 'm')
+ n *= 1024.0 * 1024.0;
+ else if (tolower(units[0]) == 'k')
+ n *= 1024.0;
+ else if (tolower(units[0]) == 't')
+ n *= 262144.0;
+ break;
+ }
+
+ *((int *)var->ptr) = (int)n;
+ }
break;
case VAR_BOOLEAN :
@@ -1173,6 +1376,7 @@ read_location(FILE *fp, /* I - Configuration file */
char *location, /* I - Location name/path */
int linenum) /* I - Current line number */
{
+ int i; /* Looping var */
location_t *loc, /* New location */
*parent; /* Parent location */
int len; /* Length of line */
@@ -1203,12 +1407,12 @@ read_location(FILE *fp, /* I - Configuration file */
continue;
/*
- * Strip trailing newline, if any...
+ * Strip trailing whitespace, if any...
*/
len = strlen(line);
- if (line[len - 1] == '\n')
+ while (len > 0 && isspace(line[len - 1]))
{
len --;
line[len] = '\0';
@@ -1290,7 +1494,12 @@ read_location(FILE *fp, /* I - Configuration file */
if (strcasecmp(value, "never") == 0)
loc->encryption = HTTP_ENCRYPT_NEVER;
else if (strcasecmp(value, "always") == 0)
- loc->encryption = HTTP_ENCRYPT_ALWAYS;
+ {
+ LogMessage(L_ERROR, "Encryption value \"%s\" on line %d is invalid in this context. "
+ "Using \"required\" instead.", value, linenum);
+
+ loc->encryption = HTTP_ENCRYPT_REQUIRED;
+ }
else if (strcasecmp(value, "required") == 0)
loc->encryption = HTTP_ENCRYPT_REQUIRED;
else if (strcasecmp(value, "ifrequested") == 0)
@@ -1429,6 +1638,13 @@ read_location(FILE *fp, /* I - Configuration file */
if (loc->level == AUTH_ANON)
loc->level = AUTH_USER;
}
+ else if (strcasecmp(value, "basicdigest") == 0)
+ {
+ loc->type = AUTH_BASICDIGEST;
+
+ if (loc->level == AUTH_ANON)
+ loc->level = AUTH_USER;
+ }
else
LogMessage(L_WARN, "Unknown authorization type %s on line %d.",
value, linenum);
@@ -1451,7 +1667,9 @@ read_location(FILE *fp, /* I - Configuration file */
else if (strcasecmp(value, "system") == 0)
{
loc->level = AUTH_GROUP;
- AddName(loc, SystemGroup);
+
+ for (i = 0; i < NumSystemGroups; i ++)
+ AddName(loc, SystemGroups[i]);
}
else
LogMessage(L_WARN, "Unknown authorization class %s on line %d.",
@@ -1510,7 +1728,7 @@ read_location(FILE *fp, /* I - Configuration file */
{
if (strcasecmp(value, "all") == 0)
loc->satisfy = AUTH_SATISFY_ALL;
- if (strcasecmp(value, "any") == 0)
+ else if (strcasecmp(value, "any") == 0)
loc->satisfy = AUTH_SATISFY_ANY;
else
LogMessage(L_WARN, "Unknown Satisfy value %s on line %d.", value,
@@ -1599,11 +1817,11 @@ get_address(const char *value, /* I - Value string */
* Decode the hostname and port number as needed...
*/
- if (hostname[0] != '\0')
+ if (hostname[0] && strcmp(hostname, "*") != 0)
{
- if ((host = gethostbyname(hostname)) == NULL)
+ if ((host = httpGetHostByName(hostname)) == NULL)
{
- LogMessage(L_ERROR, "gethostbyname(\"%s\") failed - %s!", hostname,
+ LogMessage(L_ERROR, "httpGetHostByName(\"%s\") failed - %s!", hostname,
strerror(errno));
return (0);
}
@@ -1777,5 +1995,5 @@ get_addr_and_mask(const char *value, /* I - String from config file */
/*
- * End of "$Id: conf.c,v 1.77.2.1 2001/04/02 19:51:48 mike Exp $".
+ * End of "$Id: conf.c,v 1.77.2.2 2001/12/26 16:52:51 mike Exp $".
*/
diff --git a/scheduler/conf.h b/scheduler/conf.h
index c01210a206..76790818a7 100644
--- a/scheduler/conf.h
+++ b/scheduler/conf.h
@@ -1,5 +1,5 @@
/*
- * "$Id: conf.h,v 1.36 2001/03/14 13:45:34 mike Exp $"
+ * "$Id: conf.h,v 1.36.2.1 2001/12/26 16:52:51 mike Exp $"
*
* Configuration file definitions for the Common UNIX Printing System (CUPS)
* scheduler.
@@ -64,10 +64,12 @@ VAR char ConfigurationFile[256] VALUE(CUPS_SERVERROOT "/cupsd.conf"),
/* Root directory for binaries */
RequestRoot[1024] VALUE(CUPS_REQUESTS),
/* Directory for request files */
- DocumentRoot[1024] VALUE(CUPS_DOCROOT),
+ DocumentRoot[1024] VALUE(CUPS_DOCROOT);
/* Root directory for documents */
- SystemGroup[32],
- /* System group name */
+VAR int NumSystemGroups VALUE(0);
+ /* Number of system group names */
+VAR char SystemGroups[MAX_SYSTEM_GROUPS][32],
+ /* System group names */
AccessLog[1024] VALUE(CUPS_LOGDIR "/access_log"),
/* Access log filename */
ErrorLog[1024] VALUE(CUPS_LOGDIR "/error_log"),
@@ -92,7 +94,9 @@ VAR char ConfigurationFile[256] VALUE(CUPS_SERVERROOT "/cupsd.conf"),
/* Remote root user */
Classification[IPP_MAX_NAME] VALUE("");
/* Classification of system */
-VAR int User VALUE(1),
+VAR int ClassifyOverride VALUE(0),
+ /* Allow overrides? */
+ User VALUE(1),
/* User ID for server */
Group VALUE(0),
/* Group ID for server */
@@ -114,6 +118,10 @@ VAR int User VALUE(1),
/* Timeout between requests */
ImplicitClasses VALUE(TRUE),
/* Are classes implicitly created? */
+ ImplicitAnyClasses VALUE(FALSE),
+ /* Create AnyPrinter classes? */
+ HideImplicitMembers VALUE(TRUE),
+ /* Hide implicit class members? */
FilterLimit VALUE(0),
/* Max filter cost at any time */
FilterLevel VALUE(0),
@@ -130,6 +138,10 @@ VAR FILE *AccessFile VALUE(NULL),
/* Page log file */
VAR mime_t *MimeDatabase VALUE(NULL);
/* MIME type database */
+VAR int NumMimeTypes VALUE(0);
+ /* Number of MIME types */
+VAR const char **MimeTypes VALUE(NULL);
+ /* Array of MIME types */
#ifdef HAVE_LIBSSL
VAR char ServerCertificate[1024] VALUE("ssl/server.crt"),
@@ -151,5 +163,5 @@ extern int LogPage(job_t *job, const char *page);
/*
- * End of "$Id: conf.h,v 1.36 2001/03/14 13:45:34 mike Exp $".
+ * End of "$Id: conf.h,v 1.36.2.1 2001/12/26 16:52:51 mike Exp $".
*/
diff --git a/scheduler/cups-lpd.c b/scheduler/cups-lpd.c
index 7d6a8e0464..a76f0ae274 100644
--- a/scheduler/cups-lpd.c
+++ b/scheduler/cups-lpd.c
@@ -1,5 +1,5 @@
/*
- * "$Id: cups-lpd.c,v 1.24.2.2 2001/05/13 18:38:34 mike Exp $"
+ * "$Id: cups-lpd.c,v 1.24.2.3 2001/12/26 16:52:51 mike Exp $"
*
* Line Printer Daemon interface for the Common UNIX Printing System (CUPS).
*
@@ -43,6 +43,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -228,28 +230,26 @@ main(int argc, /* I - Number of command-line arguments */
case 0x02 : /* Receive a printer job */
syslog(LOG_INFO, "Receive print job for %s", dest);
- putchar(0);
+ /* recv_print_job() sends initial status byte */
status = recv_print_job(dest, num_defaults, defaults);
break;
case 0x03 : /* Send queue state (short) */
syslog(LOG_INFO, "Send queue state (short) for %s %s", dest, list);
- putchar(0);
+ /* send_state() sends initial status byte */
status = send_state(dest, list, 0);
break;
case 0x04 : /* Send queue state (long) */
syslog(LOG_INFO, "Send queue state (long) for %s %s", dest, list);
- putchar(0);
+ /* send_state() sends initial status byte */
status = send_state(dest, list, 1);
break;
case 0x05 : /* Remove jobs */
- putchar(0);
-
/*
* Grab the agent and skip to the list of users and/or jobs.
*/
@@ -263,6 +263,8 @@ main(int argc, /* I - Number of command-line arguments */
syslog(LOG_INFO, "Remove jobs %s on %s by %s", list, dest, agent);
status = remove_jobs(dest, agent, list);
+
+ putchar(status);
break;
}
@@ -282,7 +284,7 @@ print_file(const char *name, /* I - Printer or class name */
const char *file, /* I - File to print */
const char *title, /* I - Title of job */
const char *docname, /* I - Name of job file */
- const char *user, /* I - Title of job */
+ const char *user, /* I - Owner of job */
int num_options, /* I - Number of options */
cups_option_t *options) /* I - Options */
{
@@ -365,15 +367,21 @@ print_file(const char *name, /* I - Printer or class name */
else
jobid = attr->values[0].integer;
+ if (jobid)
+ syslog(LOG_INFO, "Print file - job ID = %d", jobid);
+ else if (response)
+ syslog(LOG_ERR, "Unable to print file - %s",
+ ippErrorString(response->request.status.status_code));
+ else
+ syslog(LOG_ERR, "Unable to print file - %s",
+ ippErrorString(cupsLastError()));
+
if (response != NULL)
ippDelete(response);
httpClose(http);
cupsLangFree(language);
- if (jobid)
- syslog(LOG_INFO, "Print file - job ID = %d", jobid);
-
return (jobid);
}
@@ -416,6 +424,9 @@ recv_print_job(const char *dest, /* I - Destination */
status = 0;
num_data = 0;
+ fd = -1;
+
+ control[0] = '\0';
strncpy(queue, dest, sizeof(queue) - 1);
queue[sizeof(queue) - 1] = '\0';
@@ -432,8 +443,13 @@ recv_print_job(const char *dest, /* I - Destination */
syslog(LOG_ERR, "Unknown destination %s!", queue);
cupsFreeDests(num_dests, dests);
+
+ putchar(1);
+
return (1);
}
+ else
+ putchar(0);
while (smart_gets(line, sizeof(line), stdin) != NULL)
{
@@ -465,16 +481,38 @@ recv_print_job(const char *dest, /* I - Destination */
break;
}
- if ((fd = cupsTempFd(control, sizeof(control))) < 0)
+ if (control[0])
{
- syslog(LOG_ERR, "Unable to open temporary control file - %s",
- strerror(errno));
- putchar(1);
- status = 1;
- break;
- }
+ /*
+ * Append to the existing control file - the LPD spec is
+ * not entirely clear, but at least the OS/2 LPD code sends
+ * multiple control files per connection...
+ */
+
+ if ((fd = open(control, O_WRONLY)) < 0)
+ {
+ syslog(LOG_ERR, "Unable to append to temporary control file - %s",
+ strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
- strcpy(filename, control);
+ lseek(fd, 0, SEEK_END);
+ }
+ else
+ {
+ if ((fd = cupsTempFd(control, sizeof(control))) < 0)
+ {
+ syslog(LOG_ERR, "Unable to open temporary control file - %s",
+ strerror(errno));
+ putchar(1);
+ status = 1;
+ break;
+ }
+
+ strcpy(filename, control);
+ }
break;
case 0x03 : /* Receive data file */
if (strlen(name) < 2)
@@ -649,13 +687,14 @@ recv_print_job(const char *dest, /* I - Destination */
case 't' : /* Print troff output file */
case 'v' : /* Print raster file */
/*
- * Verify that we have a username...
+ * Check that we have a username...
*/
if (!user[0])
{
- status = 1;
- break;
+ syslog(LOG_WARNING, "No username specified by client! "
+ "Using \"anonymous\"...");
+ strcpy(user, "anonymous");
}
/*
@@ -765,7 +804,10 @@ remove_jobs(const char *dest, /* I - Destination */
if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption())) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to connect to server: %s", strerror(errno));
return (1);
+ }
language = cupsLangDefault();
@@ -849,7 +891,7 @@ remove_jobs(const char *dest, /* I - Destination */
/*
- * 'send_short_state()' - Send the short queue state.
+ * 'send_state()' - Send the queue state.
*/
int /* O - Command status */
@@ -919,7 +961,11 @@ send_state(const char *dest, /* I - Destination */
if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
cupsEncryption())) == NULL)
+ {
+ syslog(LOG_ERR, "Unable to connect to server: %s", strerror(errno));
+ putchar(1);
return (1);
+ }
/*
* Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following
@@ -961,8 +1007,11 @@ send_state(const char *dest, /* I - Destination */
syslog(LOG_WARNING, "Unable to get printer list: %s\n",
ippErrorString(response->request.status.status_code));
ippDelete(response);
+ putchar(1);
return (1);
}
+ else
+ putchar(0);
if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL)
state = (ipp_pstate_t)attr->values[0].integer;
@@ -988,6 +1037,7 @@ send_state(const char *dest, /* I - Destination */
{
syslog(LOG_WARNING, "Unable to get printer list: %s\n",
ippErrorString(cupsLastError()));
+ putchar(1);
return (1);
}
@@ -1238,5 +1288,5 @@ smart_gets(char *s, /* I - Pointer to line buffer */
/*
- * End of "$Id: cups-lpd.c,v 1.24.2.2 2001/05/13 18:38:34 mike Exp $".
+ * End of "$Id: cups-lpd.c,v 1.24.2.3 2001/12/26 16:52:51 mike Exp $".
*/
diff --git a/scheduler/cups-polld.c b/scheduler/cups-polld.c
index 6cbac56687..3932806a2f 100644
--- a/scheduler/cups-polld.c
+++ b/scheduler/cups-polld.c
@@ -1,5 +1,5 @@
/*
- * "$Id: cups-polld.c,v 1.5.2.1 2001/05/13 18:38:35 mike Exp $"
+ * "$Id: cups-polld.c,v 1.5.2.2 2001/12/26 16:52:52 mike Exp $"
*
* Polling daemon for the Common UNIX Printing System (CUPS).
*
@@ -23,6 +23,8 @@
*
* Contents:
*
+ * main() - Open socks and poll until we are killed...
+ * poll_server() - Poll the server for the given set of printers or classes.
*/
/*
@@ -118,11 +120,8 @@ main(int argc, /* I - Number of command-line arguments */
for (;;)
{
- if (poll_server(http, language, CUPS_GET_PRINTERS, sock, port))
- continue;
-
- if (poll_server(http, language, CUPS_GET_CLASSES, sock, port))
- continue;
+ if (!poll_server(http, language, CUPS_GET_PRINTERS, sock, port))
+ poll_server(http, language, CUPS_GET_CLASSES, sock, port);
sleep(interval);
}
@@ -151,6 +150,15 @@ poll_server(http_t *http, /* I - HTTP connection */
ipp_pstate_t state; /* printer-state */
struct sockaddr_in addr; /* Broadcast address */
char packet[1540]; /* Data packet */
+ static const char *attrs[] = /* Requested attributes */
+ {
+ "printer-info",
+ "printer-location",
+ "printer-make-and-model",
+ "printer-state",
+ "printer-type",
+ "printer-uri-supported"
+ };
/*
@@ -180,6 +188,10 @@ poll_server(http_t *http, /* I - HTTP connection */
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
"attributes-natural-language", NULL, language->language);
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", sizeof(attrs) / sizeof(attrs[0]),
+ NULL, attrs);
+
/*
* Do the request and get back a response...
*/
@@ -305,5 +317,5 @@ poll_server(http_t *http, /* I - HTTP connection */
/*
- * End of "$Id: cups-polld.c,v 1.5.2.1 2001/05/13 18:38:35 mike Exp $".
+ * End of "$Id: cups-polld.c,v 1.5.2.2 2001/12/26 16:52:52 mike Exp $".
*/
diff --git a/scheduler/cupsd.h b/scheduler/cupsd.h
index 73d6420614..5640089800 100644
--- a/scheduler/cupsd.h
+++ b/scheduler/cupsd.h
@@ -1,5 +1,5 @@
/*
- * "$Id: cupsd.h,v 1.28 2001/02/21 17:01:17 mike Exp $"
+ * "$Id: cupsd.h,v 1.28.2.1 2001/12/26 16:52:52 mike Exp $"
*
* Main header file for the Common UNIX Printing System (CUPS) scheduler.
*
@@ -72,6 +72,7 @@
#define MAX_LISTENERS 10 /* Maximum number of listener sockets */
#define MAX_USERPASS 33 /* Maximum size of username/password */
#define MAX_FILTERS 20 /* Maximum number of filters */
+#define MAX_SYSTEM_GROUPS 32 /* Maximum number of system groups */
/*
@@ -83,15 +84,9 @@
#define DEFAULT_TIMEOUT 300 /* Timeout during requests/updates */
#define DEFAULT_KEEPALIVE 60 /* Timeout between requests */
#define DEFAULT_INTERVAL 30 /* Interval between browse updates */
-#ifdef WIN32 /* Fix for broken Linux setlocale() */
-# define DEFAULT_LANGUAGE setlocale(LC_ALL,"")
+#define DEFAULT_LANGUAGE setlocale(LC_ALL,"")
/* Default language encoding */
-#else
-# define DEFAULT_LANGUAGE getenv("LANG")
- /* Default language encoding */
-#endif /* !WIN32 */
-#define DEFAULT_CHARSET "utf-8"
- /* Default charset */
+#define DEFAULT_CHARSET "utf-8" /* Default charset */
/*
@@ -114,12 +109,12 @@
#include "cert.h"
#include "client.h"
#include "auth.h"
-#include "dirsvc.h"
#include "printers.h"
#include "classes.h"
#include "job.h"
#include "conf.h"
#include "banners.h"
+#include "dirsvc.h"
/*
@@ -177,5 +172,5 @@ extern void StopServer(void);
/*
- * End of "$Id: cupsd.h,v 1.28 2001/02/21 17:01:17 mike Exp $".
+ * End of "$Id: cupsd.h,v 1.28.2.1 2001/12/26 16:52:52 mike Exp $".
*/
diff --git a/scheduler/devices.c b/scheduler/devices.c
index f6ac455617..3183200a74 100644
--- a/scheduler/devices.c
+++ b/scheduler/devices.c
@@ -1,5 +1,5 @@
/*
- * "$Id: devices.c,v 1.14 2001/03/23 13:58:17 mike Exp $"
+ * "$Id: devices.c,v 1.14.2.1 2001/12/26 16:52:52 mike Exp $"
*
* Device scanning routines for the Common UNIX Printing System (CUPS).
*
@@ -184,10 +184,13 @@ LoadDevices(const char *d) /* I - Directory to scan */
* Bad format; strip trailing newline and write an error message.
*/
- line[strlen(line) - 1] = '\0';
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
LogMessage(L_ERROR, "LoadDevices: Bad line from \"%s\": %s",
dent->d_name, line);
compat = 1;
+ break;
}
else
{
@@ -475,5 +478,5 @@ sigalrm_handler(int sig) /* I - Signal number */
/*
- * End of "$Id: devices.c,v 1.14 2001/03/23 13:58:17 mike Exp $".
+ * End of "$Id: devices.c,v 1.14.2.1 2001/12/26 16:52:52 mike Exp $".
*/
diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c
index a3dc19fe74..dfad0ea948 100644
--- a/scheduler/dirsvc.c
+++ b/scheduler/dirsvc.c
@@ -1,5 +1,5 @@
/*
- * "$Id: dirsvc.c,v 1.73.2.2 2001/05/13 18:38:35 mike Exp $"
+ * "$Id: dirsvc.c,v 1.73.2.3 2001/12/26 16:52:52 mike Exp $"
*
* Directory services routines for the Common UNIX Printing System (CUPS).
*
@@ -23,12 +23,21 @@
*
* Contents:
*
- * StartBrowsing() - Start sending and receiving broadcast information.
- * StopBrowsing() - Stop sending and receiving broadcast information.
- * UpdateBrowseList() - Update the browse lists for any new browse data.
- * SendBrowseList() - Send new browsing information.
- * StartPolling() - Start polling servers as needed.
- * StopPolling() - Stop polling servers as needed.
+ * ProcessBrowseData() - Process new browse data.
+ * SendBrowseList() - Send new browsing information as necessary.
+ * SendCUPSBrowse() - Send new browsing information using the CUPS protocol.
+ * StartBrowsing() - Start sending and receiving broadcast information.
+ * StartPolling() - Start polling servers as needed.
+ * StopBrowsing() - Stop sending and receiving broadcast information.
+ * StopPolling() - Stop polling servers as needed.
+ * UpdateCUPSBrowse() - Update the browse lists using the CUPS protocol.
+ * RegReportCallback() - Empty SLPRegReport.
+ * SendSLPBrowse() - Register the specified printer with SLP.
+ * SLPDeregPrinter() - SLPDereg() the specified printer
+ * GetSlpAttrVal() - Get an attribute from an SLP registration.
+ * AttrCallback() - SLP attribute callback
+ * SrvUrlCallback() - SLP service url callback
+ * UpdateSLPBrowse() - Get browsing information via SLP.
*/
/*
@@ -39,6 +48,531 @@
#include
+/*
+ * 'ProcessBrowseData()' - Process new browse data.
+ */
+
+void
+ProcessBrowseData(const char *uri, /* I - URI of printer/class */
+ cups_ptype_t type, /* I - Printer type */
+ ipp_pstate_t state, /* I - Printer state */
+ const char *location,/* I - Printer location */
+ const char *info, /* I - Printer information */
+ const char *make_model) /* I - Printer make and model */
+{
+ int i; /* Looping var */
+ int update; /* Update printer attributes? */
+ char method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ char name[IPP_MAX_NAME], /* Name of printer */
+ *hptr, /* Pointer into hostname */
+ *sptr; /* Pointer into ServerName */
+ char local_make_model[IPP_MAX_NAME];
+ /* Local make and model */
+ printer_t *p, /* Printer information */
+ *pclass, /* Printer class */
+ *first, /* First printer in class */
+ *next; /* Next printer in list */
+ int offset, /* Offset of name */
+ len; /* Length of name */
+
+
+ /*
+ * Pull the URI apart to see if this is a local or remote printer...
+ */
+
+ httpSeparate(uri, method, username, host, &port, resource);
+
+ /*
+ * OK, this isn't a local printer; see if we already have it listed in
+ * the Printers list, and add it if not...
+ */
+
+ update = 0;
+ hptr = strchr(host, '.');
+ sptr = strchr(ServerName, '.');
+
+ if (sptr != NULL && hptr != NULL)
+ {
+ /*
+ * Strip the common domain name components...
+ */
+
+ while (hptr != NULL)
+ {
+ if (strcasecmp(hptr, sptr) == 0)
+ {
+ *hptr = '\0';
+ break;
+ }
+ else
+ hptr = strchr(hptr + 1, '.');
+ }
+ }
+
+ if (type & CUPS_PRINTER_CLASS)
+ {
+ /*
+ * Remote destination is a class...
+ */
+
+ if (strncmp(resource, "/classes/", 9) == 0)
+ snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
+ else
+ return;
+
+ if ((p = FindClass(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = FindClass(resource + 9)) != NULL)
+ {
+ if (strcasecmp(p->hostname, host) != 0 && p->hostname[0])
+ {
+ /*
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other class and then find a class using the full host
+ * name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncat(p->name, "@", sizeof(p->name) - 1);
+ strncat(p->name, p->hostname, sizeof(p->name) - 1);
+ SetPrinterAttrs(p);
+ SortPrinters();
+ }
+
+ p = NULL;
+ }
+ else if (!p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+ }
+ else
+ {
+ strncpy(name, resource + 9, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ }
+ }
+ else if (p != NULL && !p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+
+ if (p == NULL)
+ {
+ /*
+ * Class doesn't exist; add it...
+ */
+
+ p = AddClass(name);
+
+ LogMessage(L_INFO, "Added remote class \"%s\"...", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type;
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+
+ update = 1;
+ }
+ }
+ else
+ {
+ /*
+ * Remote destination is a printer...
+ */
+
+ if (strncmp(resource, "/printers/", 10) == 0)
+ snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
+ else
+ return;
+
+ if ((p = FindPrinter(name)) == NULL && BrowseShortNames)
+ {
+ if ((p = FindPrinter(resource + 10)) != NULL)
+ {
+ if (strcasecmp(p->hostname, host) != 0 && p->hostname[0])
+ {
+ /*
+ * Nope, this isn't the same host; if the hostname isn't the local host,
+ * add it to the other printer and then find a printer using the full host
+ * name...
+ */
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncat(p->name, "@", sizeof(p->name) - 1);
+ strncat(p->name, p->hostname, sizeof(p->name) - 1);
+ SetPrinterAttrs(p);
+ SortPrinters();
+ }
+
+ p = NULL;
+ }
+ else if (!p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+ }
+ else
+ {
+ strncpy(name, resource + 10, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ }
+ }
+ else if (p != NULL && !p->hostname[0])
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ update = 1;
+ }
+
+ if (p == NULL)
+ {
+ /*
+ * Printer doesn't exist; add it...
+ */
+
+ p = AddPrinter(name);
+
+ LogMessage(L_INFO, "Added remote printer \"%s\"...", name);
+
+ /*
+ * Force the URI to point to the real server...
+ */
+
+ p->type = type;
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+ strncpy(p->uri, uri, sizeof(p->uri) - 1);
+ strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+
+ update = 1;
+ }
+ }
+
+ /*
+ * Update the state...
+ */
+
+ p->state = state;
+ p->accepting = state != IPP_PRINTER_STOPPED;
+ p->browse_time = time(NULL);
+
+ if (p->type != type)
+ {
+ p->type = type;
+ update = 1;
+ }
+
+ if (strcmp(p->location, location))
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->location, location, sizeof(p->location) - 1);
+ update = 1;
+ }
+
+ if (strcmp(p->info, info))
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->info, info, sizeof(p->info) - 1);
+ update = 1;
+ }
+
+ if (!make_model[0])
+ {
+ if (type & CUPS_PRINTER_CLASS)
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Class on %s", host);
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "Remote Printer on %s", host);
+ }
+ else
+ snprintf(local_make_model, sizeof(local_make_model),
+ "%s on %s", make_model, host);
+
+ if (strcmp(p->make_model, local_make_model))
+ {
+ /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
+ strncpy(p->make_model, local_make_model, sizeof(p->make_model) - 1);
+ update = 1;
+ }
+
+ if (update)
+ SetPrinterAttrs(p);
+
+ /*
+ * See if we have a default printer... If not, make the first printer the
+ * default.
+ */
+
+ if (DefaultPrinter == NULL && Printers != NULL)
+ DefaultPrinter = Printers;
+
+ /*
+ * Do auto-classing if needed...
+ */
+
+ if (ImplicitClasses)
+ {
+ /*
+ * Loop through all available printers and create classes as needed...
+ */
+
+ for (p = Printers, len = 0, offset = 0, first = NULL;
+ p != NULL;
+ p = next)
+ {
+ /*
+ * Get next printer in list...
+ */
+
+ next = p->next;
+
+ /*
+ * Skip classes...
+ */
+
+ if (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS))
+ {
+ len = 0;
+ continue;
+ }
+
+ /*
+ * If len == 0, get the length of this printer name up to the "@"
+ * sign (if any).
+ */
+
+ if (len > 0 &&
+ strncasecmp(p->name, name + offset, len) == 0 &&
+ (p->name[len] == '\0' || p->name[len] == '@'))
+ {
+ /*
+ * We have more than one printer with the same name; see if
+ * we have a class, and if this printer is a member...
+ */
+
+ if ((pclass = FindPrinter(name)) == NULL)
+ {
+ /*
+ * Need to add the class...
+ */
+
+ pclass = AddPrinter(name);
+ pclass->type |= CUPS_PRINTER_IMPLICIT;
+ pclass->accepting = 1;
+ pclass->state = IPP_PRINTER_IDLE;
+
+ SetPrinterAttrs(pclass);
+
+ LogMessage(L_INFO, "Added implicit class \"%s\"...", name);
+ }
+
+ if (first != NULL)
+ {
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == first)
+ break;
+
+ if (i >= pclass->num_printers)
+ AddPrinterToClass(pclass, first);
+
+ first = NULL;
+ }
+
+ for (i = 0; i < pclass->num_printers; i ++)
+ if (pclass->printers[i] == p)
+ break;
+
+ if (i >= pclass->num_printers)
+ AddPrinterToClass(pclass, p);
+ }
+ else
+ {
+ /*
+ * First time around; just get name length and mark it as first
+ * in the list...
+ */
+
+ if ((hptr = strchr(p->name, '@')) != NULL)
+ len = hptr - p->name;
+ else
+ len = strlen(p->name);
+
+ strncpy(name, p->name, len);
+ name[len] = '\0';
+ offset = 0;
+
+ if ((pclass = FindPrinter(name)) != NULL &&
+ !(pclass->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Can't use same name as a local printer; add "Any" to the
+ * front of the name, unless we have explicitly disabled
+ * the "ImplicitAnyClasses"...
+ */
+
+ if (ImplicitAnyClasses)
+ {
+ /*
+ * Add "Any" to the class name...
+ */
+
+ strcpy(name, "Any");
+ strncpy(name + 3, p->name, len);
+ name[len + 3] = '\0';
+ offset = 3;
+ }
+ else
+ {
+ /*
+ * Don't create an implicit class if we have a local printer
+ * with the same name...
+ */
+
+ len = 0;
+ continue;
+ }
+ }
+
+ first = p;
+ }
+ }
+ }
+}
+
+
+/*
+ * 'SendBrowseList()' - Send new browsing information as necessary.
+ */
+
+void
+SendBrowseList(void)
+{
+ printer_t *p, /* Current printer */
+ *np; /* Next printer */
+ time_t ut, /* Minimum update time */
+ to; /* Timeout time */
+
+
+ if (!Browsing || !(BrowseProtocols & BROWSE_CUPS))
+ return;
+
+ /*
+ * Compute the update and timeout times...
+ */
+
+ ut = time(NULL) - BrowseInterval;
+ to = time(NULL) - BrowseTimeout;
+
+ /*
+ * Loop through all of the printers and send local updates as needed...
+ */
+
+ for (p = Printers; p != NULL; p = np)
+ {
+ np = p->next;
+
+ if (p->type & CUPS_PRINTER_REMOTE)
+ {
+ /*
+ * See if this printer needs to be timed out...
+ */
+
+ if (p->browse_time < to)
+ {
+ LogMessage(L_INFO, "Remote destination \"%s\" has timed out; deleting it...",
+ p->name);
+ DeletePrinter(p);
+ }
+ }
+ else if (p->browse_time < ut && BrowseInterval > 0 &&
+ !(p->type & CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Need to send an update...
+ */
+
+ p->browse_time = time(NULL);
+
+ if (BrowseProtocols & BROWSE_CUPS)
+ SendCUPSBrowse(p);
+
+#ifdef HAVE_LIBSLP
+ if (BrowseProtocols & BROWSE_SLP)
+ SendSLPBrowse(p);
+#endif /* HAVE_LIBSLP */
+ }
+ }
+}
+
+
+/*
+ * 'SendCUPSBrowse()' - Send new browsing information using the CUPS protocol.
+ */
+
+void
+SendCUPSBrowse(printer_t *p) /* I - Printer to send */
+{
+ int i; /* Looping var */
+ int bytes; /* Length of packet */
+ char packet[1453];
+ /* Browse data packet */
+
+
+ snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
+ p->type | CUPS_PRINTER_REMOTE, p->state, p->uri,
+ p->location, p->info, p->make_model);
+
+ bytes = strlen(packet);
+ LogMessage(L_DEBUG2, "SendBrowseList: (%d bytes) %s", bytes, packet);
+
+ /*
+ * Send a packet to each browse address...
+ */
+
+ for (i = 0; i < NumBrowsers; i ++)
+ if (sendto(BrowseSocket, packet, bytes, 0,
+ (struct sockaddr *)Browsers + i, sizeof(Browsers[0])) <= 0)
+ {
+ LogMessage(L_ERROR, "SendBrowseList: sendto failed for browser %d - %s.",
+ i + 1, strerror(errno));
+ LogMessage(L_ERROR, "Browsing turned off.");
+
+ StopBrowsing();
+ Browsing = 0;
+ return;
+ }
+}
+
+
/*
* 'StartBrowsing()' - Start sending and receiving broadcast information.
*/
@@ -53,112 +587,243 @@ StartBrowsing(void)
if (!Browsing)
return;
- /*
- * Create the broadcast socket...
- */
+ if (BrowseProtocols & BROWSE_CUPS)
+ {
+ /*
+ * Create the broadcast socket...
+ */
+
+ if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ LogMessage(L_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.",
+ strerror(errno));
+ Browsing = 0;
+ return;
+ }
+
+ /*
+ * Set the "broadcast" flag...
+ */
+
+ val = 1;
+ if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+ {
+ LogMessage(L_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.",
+ strerror(errno));
+
+ #if defined(WIN32) || defined(__EMX__)
+ closesocket(BrowseSocket);
+ #else
+ close(BrowseSocket);
+ #endif /* WIN32 || __EMX__ */
+
+ BrowseSocket = -1;
+ Browsing = 0;
+ return;
+ }
+
+ /*
+ * Bind the socket to browse port...
+ */
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(BrowsePort);
+
+ if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
+ {
+ LogMessage(L_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.",
+ strerror(errno));
- if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ #if defined(WIN32) || defined(__EMX__)
+ closesocket(BrowseSocket);
+ #else
+ close(BrowseSocket);
+ #endif /* WIN32 || __EMX__ */
+
+ BrowseSocket = -1;
+ Browsing = 0;
+ return;
+ }
+
+ /*
+ * Finally, add the socket to the input selection set...
+ */
+
+ LogMessage(L_DEBUG2, "StartBrowsing: Adding fd %d to InputSet...",
+ BrowseSocket);
+
+ FD_SET(BrowseSocket, &InputSet);
+ }
+
+#ifdef HAVE_LIBSLP
+ if (BrowseProtocols & BROWSE_SLP)
{
- LogMessage(L_ERROR, "StartBrowsing: Unable to create broadcast socket - %s.",
- strerror(errno));
- Browsing = 0;
- return;
+ /*
+ * Open SLP handle...
+ */
+
+ if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK)
+ {
+ LogMessage(L_ERROR, "Unable to open an SLP handle; disabling SLP browsing!");
+ BrowseProtocols &= ~BROWSE_SLP;
+ }
+
+ BrowseSLPRefresh = 0;
}
+}
- /*
- * Set the "broadcast" flag...
- */
- val = 1;
- if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val)))
+/*
+ * 'StartPolling()' - Start polling servers as needed.
+ */
+
+void
+StartPolling(void)
+{
+ int i; /* Looping var */
+ dirsvc_poll_t *poll; /* Current polling server */
+ int pid; /* New process ID */
+ char sport[10]; /* Server port */
+ char bport[10]; /* Browser port */
+ char interval[10]; /* Poll interval */
+
+
+ sprintf(bport, "%d", BrowsePort);
+
+ if (BrowseInterval)
+ sprintf(interval, "%d", BrowseInterval);
+ else
+ strcpy(interval, "30");
+
+ for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
{
- LogMessage(L_ERROR, "StartBrowsing: Unable to set broadcast mode - %s.",
- strerror(errno));
+ sprintf(sport, "%d", poll->port);
-#if defined(WIN32) || defined(__EMX__)
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 || __EMX__ */
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child...
+ */
- BrowseSocket = -1;
- Browsing = 0;
- return;
+ if (getuid() == 0)
+ {
+ /*
+ * Running as root, so change to non-priviledged user...
+ */
+
+ if (setgid(Group))
+ exit(errno);
+
+ if (setuid(User))
+ exit(errno);
+ }
+
+ /*
+ * Reset group membership to just the main one we belong to.
+ */
+
+ setgroups(0, NULL);
+
+ /*
+ * Execute the polling daemon...
+ */
+
+ execl(CUPS_SERVERBIN "/daemon/cups-polld", "cups-polld", poll->hostname,
+ sport, interval, bport, NULL);
+ exit(errno);
+ }
+ else if (pid < 0)
+ {
+ LogMessage(L_ERROR, "StartPolling: Unable to fork polling daemon - %s",
+ strerror(errno));
+ poll->pid = 0;
+ break;
+ }
+ else
+ {
+ poll->pid = pid;
+ LogMessage(L_DEBUG, "StartPolling: Started polling daemon for %s:%d, pid = %d",
+ poll->hostname, poll->port, pid);
+ }
}
+>>>>>>> 1.86
+}
- /*
- * Bind the socket to browse port...
- */
- memset(&addr, 0, sizeof(addr));
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_family = AF_INET;
- addr.sin_port = htons(BrowsePort);
+/*
+ * 'StopBrowsing()' - Stop sending and receiving broadcast information.
+ */
+
+void
+StopBrowsing(void)
+{
+ if (!Browsing)
+ return;
- if (bind(BrowseSocket, (struct sockaddr *)&addr, sizeof(addr)))
+ if (BrowseProtocols & BROWSE_CUPS)
{
- LogMessage(L_ERROR, "StartBrowsing: Unable to bind broadcast socket - %s.",
- strerror(errno));
+ /*
+ * Close the socket and remove it from the input selection set.
+ */
+ if (BrowseSocket >= 0)
+ {
#if defined(WIN32) || defined(__EMX__)
- closesocket(BrowseSocket);
+ closesocket(BrowseSocket);
#else
- close(BrowseSocket);
+ close(BrowseSocket);
#endif /* WIN32 || __EMX__ */
- BrowseSocket = -1;
- Browsing = 0;
- return;
+ LogMessage(L_DEBUG2, "StopBrowsing: Removing fd %d from InputSet...",
+ BrowseSocket);
+
+ FD_CLR(BrowseSocket, &InputSet);
+ BrowseSocket = 0;
+ }
}
- /*
- * Finally, add the socket to the input selection set...
- */
+#ifdef HAVE_LIBSLP
+ if (BrowseProtocols & BROWSE_SLP)
+ {
+ /*
+ * Close SLP handle...
+ */
- FD_SET(BrowseSocket, &InputSet);
+ SLPClose(BrowseSLPHandle);
+ }
+#endif /* HAVE_LIBSLP */
}
/*
- * 'StopBrowsing()' - Stop sending and receiving broadcast information.
+ * 'StopPolling()' - Stop polling servers as needed.
*/
void
-StopBrowsing(void)
+StopPolling(void)
{
- if (!Browsing)
- return;
-
- /*
- * Close the socket and remove it from the input selection set.
- */
+ int i; /* Looping var */
+ dirsvc_poll_t *poll; /* Current polling server */
- if (BrowseSocket >= 0)
- {
-#if defined(WIN32) || defined(__EMX__)
- closesocket(BrowseSocket);
-#else
- close(BrowseSocket);
-#endif /* WIN32 || __EMX__ */
- FD_CLR(BrowseSocket, &InputSet);
- BrowseSocket = 0;
- }
+ for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
+ if (poll->pid)
+ kill(poll->pid, SIGTERM);
}
/*
- * 'UpdateBrowseList()' - Update the browse lists for any new browse data.
+ * 'UpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol.
*/
void
-UpdateBrowseList(void)
+UpdateCUPSBrowse(void)
{
int i; /* Looping var */
- int update; /* Update printer attributes? */
int auth; /* Authorization status */
- int len, /* Length of name string */
- offset; /* Offset in name string */
+ int len; /* Length of name string */
int bytes; /* Number of bytes left */
char packet[1540], /* Broadcast packet */
*pptr; /* Pointer into packet */
@@ -177,13 +842,6 @@ UpdateBrowseList(void)
location[IPP_MAX_NAME], /* Location string */
make_model[IPP_MAX_NAME];/* Make and model string */
int port; /* Port portion of URI */
- char name[IPP_MAX_NAME], /* Name of printer */
- *hptr, /* Pointer into hostname */
- *sptr; /* Pointer into ServerName */
- printer_t *p, /* Printer information */
- *pclass, /* Printer class */
- *first, /* First printer in class */
- *next; /* Next printer in list */
/*
@@ -251,7 +909,7 @@ UpdateBrowseList(void)
* Do ACL stuff...
*/
- if (BrowseACL)
+ if (BrowseACL && (BrowseACL->num_allow || BrowseACL->num_deny))
{
if (httpAddrLocalhost(&srcaddr) || strcasecmp(srcname, "localhost") == 0)
{
@@ -316,8 +974,6 @@ UpdateBrowseList(void)
* Parse packet...
*/
- update = 0;
-
if (sscanf(packet, "%x%x%1023s", (unsigned *)&type, (unsigned *)&state,
uri) < 3)
{
@@ -412,553 +1068,521 @@ UpdateBrowseList(void)
}
/*
- * OK, this isn't a local printer; see if we already have it listed in
- * the Printers list, and add it if not...
+ * Process the browse data...
*/
- hptr = strchr(host, '.');
- sptr = strchr(ServerName, '.');
-
- if (sptr != NULL && hptr != NULL)
- {
- /*
- * Strip the common domain name components...
- */
-
- while (hptr != NULL)
- {
- if (strcasecmp(hptr, sptr) == 0)
- {
- *hptr = '\0';
- break;
- }
- else
- hptr = strchr(hptr + 1, '.');
- }
- }
-
- if (type & CUPS_PRINTER_CLASS)
- {
- /*
- * Remote destination is a class...
- */
-
- if (strncmp(resource, "/classes/", 9) == 0)
- snprintf(name, sizeof(name), "%s@%s", resource + 9, host);
- else
- return;
-
- if ((p = FindClass(name)) == NULL && BrowseShortNames)
- {
- if ((p = FindClass(resource + 9)) != NULL)
- {
- if (strcasecmp(p->hostname, host) != 0 && p->hostname[0])
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other class and then find a class using the full host
- * name...
- */
-
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncat(p->name, "@", sizeof(p->name) - 1);
- strncat(p->name, p->hostname, sizeof(p->name) - 1);
- SetPrinterAttrs(p);
- SortPrinters();
- }
+ ProcessBrowseData(uri, type, state, location, info, make_model);
+}
- p = NULL;
- }
- else if (!p->hostname[0])
- {
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->hostname, host, sizeof(p->hostname) - 1);
- strncpy(p->uri, uri, sizeof(p->uri) - 1);
- strncpy(p->more_info, uri, sizeof(p->more_info) - 1);
- strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
- update = 1;
- }
- }
- else
- {
- strncpy(name, resource + 9, sizeof(name) - 1);
- name[sizeof(name) - 1] = '\0';
- }
- }
- else if (!p->hostname[0])
- {
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->hostname, host, sizeof(p->hostname) - 1);
- strncpy(p->uri, uri, sizeof(p->uri) - 1);
- strncpy(p->more_info, uri, sizeof(p->more_info) - 1);
- strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
- update = 1;
- }
- if (p == NULL)
- {
- /*
- * Class doesn't exist; add it...
- */
+/***********************************************************************
+ **** SLP Support Code *************************************************
+ ***********************************************************************/
- p = AddClass(name);
+#ifdef HAVE_LIBSLP
+/*
+ * SLP service name for CUPS...
+ */
- /*
- * Force the URI to point to the real server...
- */
+# define SLP_CUPS_SRVTYPE "service:printer"
+# define SLP_CUPS_SRVLEN 15
- p->type = type;
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->uri, uri, sizeof(p->uri) - 1);
- strncpy(p->more_info, uri, sizeof(p->more_info) - 1);
- strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
- strncpy(p->hostname, host, sizeof(p->hostname) - 1);
+typedef struct _slpsrvurl
+{
+ struct _slpsrvurl *next;
+ char url[HTTP_MAX_URI];
+} slpsrvurl_t;
- update = 1;
- }
- }
- else
- {
- /*
- * Remote destination is a printer...
- */
- if (strncmp(resource, "/printers/", 10) == 0)
- snprintf(name, sizeof(name), "%s@%s", resource + 10, host);
- else
- return;
+/*
+ * 'RegReportCallback()' - Empty SLPRegReport.
+ */
- if ((p = FindPrinter(name)) == NULL && BrowseShortNames)
- {
- if ((p = FindPrinter(resource + 10)) != NULL)
- {
- if (strcasecmp(p->hostname, host) != 0 && p->hostname[0])
- {
- /*
- * Nope, this isn't the same host; if the hostname isn't the local host,
- * add it to the other printer and then find a printer using the full host
- * name...
- */
+void
+RegReportCallback(SLPHandle hslp,
+ SLPError errcode,
+ void *cookie)
+{
+ (void)hslp;
+ (void)errcode;
+ (void)cookie;
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncat(p->name, "@", sizeof(p->name) - 1);
- strncat(p->name, p->hostname, sizeof(p->name) - 1);
- SetPrinterAttrs(p);
- SortPrinters();
- }
+ return;
+}
- p = NULL;
- }
- else if (!p->hostname[0])
- {
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->hostname, host, sizeof(p->hostname) - 1);
- strncpy(p->uri, uri, sizeof(p->uri) - 1);
- strncpy(p->more_info, uri, sizeof(p->more_info) - 1);
- strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
- update = 1;
- }
- }
- else
- {
- strncpy(name, resource + 10, sizeof(name) - 1);
- name[sizeof(name) - 1] = '\0';
- }
- }
- else if (!p->hostname[0])
- {
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->hostname, host, sizeof(p->hostname) - 1);
- strncpy(p->uri, uri, sizeof(p->uri) - 1);
- strncpy(p->more_info, uri, sizeof(p->more_info) - 1);
- strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
- update = 1;
- }
- if (p == NULL)
- {
- /*
- * Printer doesn't exist; add it...
- */
+/*
+ * 'SendSLPBrowse()' - Register the specified printer with SLP.
+ */
- p = AddPrinter(name);
+void
+SendSLPBrowse(printer_t *p) /* I - Printer to register */
+{
+ char srvurl[HTTP_MAX_URI], /* Printer service URI */
+ attrs[8192], /* Printer attributes */
+ finishings[1024], /* Finishings to support */
+ make_model[IPP_MAX_NAME * 2],
+ /* Make and model, quoted */
+ location[IPP_MAX_NAME * 2],
+ /* Location, quoted */
+ info[IPP_MAX_NAME * 2],
+ /* Info, quoted */
+ *src, /* Pointer to original string */
+ *dst; /* Pointer to destination string */
+ ipp_attribute_t *authentication; /* uri-authentication-supported value */
+ SLPError error; /* SLP error, if any */
+
+
+ LogMessage(L_DEBUG, "SendSLPBrowse(%p = \"%s\")", p, p->name);
- /*
- * Force the URI to point to the real server...
- */
+ /*
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
+ */
- p->type = type;
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->hostname, host, sizeof(p->hostname) - 1);
- strncpy(p->uri, uri, sizeof(p->uri) - 1);
- strncpy(p->more_info, uri, sizeof(p->more_info) - 1);
- strncpy(p->device_uri, uri, sizeof(p->device_uri) - 1);
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
- update = 1;
- }
- }
+ LogMessage(L_DEBUG2, "Service URL = \"%s\"", srvurl);
/*
- * Update the state...
+ * Figure out the finishings string...
*/
- p->state = state;
- p->accepting = state != IPP_PRINTER_STOPPED;
- p->browse_time = time(NULL);
+ if (p->type & CUPS_PRINTER_STAPLE)
+ strcpy(finishings, "staple");
+ else
+ finishings[0] = '\0';
- if (p->type != type)
+ if (p->type & CUPS_PRINTER_BIND)
{
- p->type = type;
- update = 1;
+ if (finishings[0])
+ strncat(finishings, ",bind", sizeof(finishings) - 1);
+ else
+ strcpy(finishings, "bind");
}
- if (strcmp(p->location, location))
+ if (p->type & CUPS_PRINTER_PUNCH)
{
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->location, location, sizeof(p->location) - 1);
- update = 1;
+ if (finishings[0])
+ strncat(finishings, ",punch", sizeof(finishings) - 1);
+ else
+ strcpy(finishings, "punch");
}
- if (strcmp(p->info, info))
+ if (p->type & CUPS_PRINTER_COVER)
{
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->info, info, sizeof(p->info) - 1);
- update = 1;
+ if (finishings[0])
+ strncat(finishings, ",cover", sizeof(finishings) - 1);
+ else
+ strcpy(finishings, "cover");
}
- if (!make_model[0])
+ if (p->type & CUPS_PRINTER_SORT)
{
- if (type & CUPS_PRINTER_CLASS)
- snprintf(make_model, sizeof(p->make_model), "Remote Class on %s",
- host);
+ if (finishings[0])
+ strncat(finishings, ",sort", sizeof(finishings) - 1);
else
- snprintf(make_model, sizeof(p->make_model), "Remote Printer on %s",
- host);
+ strcpy(finishings, "sort");
}
- else
+
+ if (!finishings[0])
+ strcpy(finishings, "none");
+
+ finishings[sizeof(finishings) - 1] = '\0';
+
+ /*
+ * Quote any commas in the make and model, location, and info strings
+ * (local strings are twice the size of the ones in the printer_t
+ * structure, so no buffer overflow is possible...)
+ */
+
+ for (src = p->make_model, dst = make_model; *src;)
+ {
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ if (!make_model[0])
+ strcpy(make_model, "Unknown");
+
+ for (src = p->location, dst = location; *src;)
{
- strncat(make_model, " on ", sizeof(make_model) - 1);
- strncat(make_model, host, sizeof(make_model) - 1);
- make_model[sizeof(make_model) - 1] = '\0';
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
}
- if (strcmp(p->make_model, make_model))
+ *dst = '\0';
+
+ if (!location[0])
+ strcpy(location, "Unknown");
+
+ for (src = p->info, dst = info; *src;)
{
- /* No "p->var[sizeof(p->var) - 1] = '\0';" because p is zeroed */
- strncpy(p->make_model, make_model, sizeof(p->make_model) - 1);
- update = 1;
+ if (*src == ',' || *src == '\\' || *src == ')')
+ *dst++ = '\\';
+
+ *dst++ = *src++;
}
- if (update)
- SetPrinterAttrs(p);
+ *dst = '\0';
+
+ if (!info[0])
+ strcpy(info, "Unknown");
+
+ /*
+ * Get the authentication value...
+ */
+
+ authentication = ippFindAttribute(p->attrs, "uri-authentication-supported",
+ IPP_TAG_KEYWORD);
/*
- * See if we have a default printer... If not, make the first printer the
- * default.
+ * Make the SLP attribute string list that conforms to
+ * the IANA 'printer:' template.
*/
- if (DefaultPrinter == NULL && Printers != NULL)
- DefaultPrinter = Printers;
+ snprintf(attrs, sizeof(attrs),
+ "(printer-uri-supported=%s),"
+ "(uri-authentication-supported=%s>),"
+#ifdef HAVE_LIBSSL
+ "(uri-security-supported=tls>),"
+#else
+ "(uri-security-supported=none>),"
+#endif /* HAVE_LIBSSL */
+ "(printer-name=%s),"
+ "(printer-location=%s),"
+ "(printer-info=%s),"
+ "(printer-more-info=%s),"
+ "(printer-make-and-model=%s),"
+ "(charset-supported=utf-8),"
+ "(natural-language-configured=%s),"
+ "(natural-language-supported=de,en,es,fr,it),"
+ "(color-supported=%s),"
+ "(finishings-supported=%s),"
+ "(sides-supported=one-sided%s),"
+ "(multiple-document-jobs-supported=true)"
+ "(ipp-versions-supported=1.0,1.1)",
+ p->uri, authentication->values[0].string.text, p->name, location,
+ info, p->uri, make_model, DefaultLanguage,
+ p->type & CUPS_PRINTER_COLOR ? "true" : "false",
+ finishings,
+ p->type & CUPS_PRINTER_DUPLEX ?
+ ",two-sided-long-edge,two-sided-short-edge" : "");
+
+ LogMessage(L_DEBUG2, "Attributes = \"%s\"", attrs);
/*
- * Do auto-classing if needed...
+ * Register the printer with the SLP server...
*/
- if (ImplicitClasses)
+ error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout,
+ SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, RegReportCallback, 0);
+
+ if (error != SLP_OK)
+ LogMessage(L_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name,
+ error);
+}
+
+
+/*
+ * 'SLPDeregPrinter()' - SLPDereg() the specified printer
+ */
+
+void
+SLPDeregPrinter(printer_t *p)
+{
+ char srvurl[HTTP_MAX_URI]; /* Printer service URI */
+
+
+ if((p->type & CUPS_PRINTER_REMOTE) == 0)
{
/*
- * Loop through all available printers and create classes as needed...
+ * Make the SLP service URL that conforms to the IANA
+ * 'printer:' template.
*/
- for (p = Printers, len = 0, offset = 0, first = NULL;
- p != NULL;
- p = next)
- {
- /*
- * Get next printer in list...
- */
+ snprintf(srvurl, sizeof(srvurl), SLP_CUPS_SRVTYPE ":%s", p->uri);
- next = p->next;
+ /*
+ * Deregister the printer...
+ */
- /*
- * Skip classes...
- */
+ SLPDereg(BrowseSLPHandle, srvurl, RegReportCallback, 0);
+ }
+}
- if (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS))
- {
- len = 0;
- continue;
- }
- /*
- * If len == 0, get the length of this printer name up to the "@"
- * sign (if any).
- */
+/*
+ * 'GetSlpAttrVal()' - Get an attribute from an SLP registration.
+ */
- if (len > 0 &&
- strncasecmp(p->name, name + offset, len) == 0 &&
- (p->name[len] == '\0' || p->name[len] == '@'))
+int /* O - 0 on success */
+GetSlpAttrVal(const char *attrlist, /* I - Attribute list string */
+ const char *tag, /* I - Name of attribute */
+ char *valbuf, /* O - Value */
+ int valbuflen) /* I - Max length of value */
+{
+ char *ptr1, /* Pointer into string */
+ *ptr2; /* ... */
+
+
+ valbuf[0] = '\0';
+
+ if ((ptr1 = strstr(attrlist, tag)) != NULL)
+ {
+ ptr1 += strlen(tag);
+
+ if ((ptr2 = strchr(ptr1,')')) != NULL)
+ {
+ if (valbuflen > (ptr2 - ptr1))
{
/*
- * We have more than one printer with the same name; see if
- * we have a class, and if this printer is a member...
+ * Copy the value...
*/
- if ((pclass = FindPrinter(name)) == NULL)
- {
- /*
- * Need to add the class...
- */
+ strncpy(valbuf, ptr1, ptr2 - ptr1);
+ valbuf[ptr2 - ptr1] = '\0';
- pclass = AddPrinter(name);
- pclass->type |= CUPS_PRINTER_IMPLICIT;
- pclass->accepting = 1;
- pclass->state = IPP_PRINTER_IDLE;
+ /*
+ * Dequote the value...
+ */
- SetPrinterAttrs(pclass);
+ for (ptr1 = valbuf; *ptr1; ptr1 ++)
+ if (*ptr1 == '\\' && ptr1[1])
+ strcpy(ptr1, ptr1 + 1);
- DEBUG_printf(("Added new class \"%s\", type = %x\n", name,
- pclass->type));
- }
+ return (0);
+ }
+ }
+ }
- if (first != NULL)
- {
- for (i = 0; i < pclass->num_printers; i ++)
- if (pclass->printers[i] == first)
- break;
+ return (-1);
+}
- if (i >= pclass->num_printers)
- AddPrinterToClass(pclass, first);
- first = NULL;
- }
+/*
+ * 'AttrCallback()' - SLP attribute callback
+ */
- for (i = 0; i < pclass->num_printers; i ++)
- if (pclass->printers[i] == p)
- break;
+SLPBoolean
+AttrCallback(SLPHandle hslp,
+ const char *attrlist,
+ SLPError errcode,
+ void *cookie)
+{
+ char tmp[IPP_MAX_NAME];
+ printer_t *p = (printer_t*)cookie;
- if (i >= pclass->num_printers)
- AddPrinterToClass(pclass, p);
- }
- else
- {
- /*
- * First time around; just get name length and mark it as first
- * in the list...
- */
- if ((hptr = strchr(p->name, '@')) != NULL)
- len = hptr - p->name;
- else
- len = strlen(p->name);
+ /*
+ * Let the compiler know we won't be using these...
+ */
- strncpy(name, p->name, len);
- name[len] = '\0';
- offset = 0;
+ (void)hslp;
- if ((pclass = FindPrinter(name)) != NULL &&
- !(pclass->type & CUPS_PRINTER_IMPLICIT))
- {
- /*
- * Can't use same name as printer; add "Any" to the front of the
- * name...
- */
+ /*
+ * Bail if there was an error
+ */
- strcpy(name, "Any");
- strncpy(name + 3, p->name, len);
- name[len + 3] = '\0';
- offset = 3;
- }
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
- first = p;
- }
- }
- }
+ /*
+ * Parse the attrlist to obtain things needed to build CUPS browse packet
+ */
+
+ memset(p, 0, sizeof(printer_t));
+
+ p->type = CUPS_PRINTER_REMOTE;
+
+ if (GetSlpAttrVal(attrlist, "(printer-location=", p->location,
+ sizeof(p->location)))
+ return (SLP_FALSE);
+ if (GetSlpAttrVal(attrlist, "(printer-make-and-model=", p->make_model,
+ sizeof(p->make_model)))
+ return (SLP_FALSE);
+
+ if (GetSlpAttrVal(attrlist, "(color-supported=", tmp, sizeof(tmp)))
+ return (SLP_FALSE);
+ if (strcasecmp(tmp, "true") == 0)
+ p->type |= CUPS_PRINTER_COLOR;
+
+ if (GetSlpAttrVal(attrlist, "(finishings-supported=", tmp, sizeof(tmp)))
+ return (SLP_FALSE);
+ if (strstr(tmp, "staple"))
+ p->type |= CUPS_PRINTER_STAPLE;
+ if (strstr(tmp, "bind"))
+ p->type |= CUPS_PRINTER_BIND;
+ if (strstr(tmp, "punch"))
+ p->type |= CUPS_PRINTER_PUNCH;
+
+ if (GetSlpAttrVal(attrlist, "(sides-supported=", tmp, sizeof(tmp)))
+ return (SLP_FALSE);
+ if (strstr(tmp,"two-sided"))
+ p->type |= CUPS_PRINTER_DUPLEX;
+
+ return (SLP_TRUE);
}
/*
- * 'SendBrowseList()' - Send new browsing information.
+ * 'SrvUrlCallback()' - SLP service url callback
*/
-void
-SendBrowseList(void)
+SLPBoolean /* O - TRUE = OK, FALSE = error */
+SrvUrlCallback(SLPHandle hslp, /* I - SLP handle */
+ const char *srvurl, /* I - URL of service */
+ unsigned short lifetime, /* I - Life of service */
+ SLPError errcode, /* I - Existing error code */
+ void *cookie) /* I - Pointer to service list */
{
- int i; /* Looping var */
- printer_t *p, /* Current printer */
- *np; /* Next printer */
- time_t ut, /* Minimum update time */
- to; /* Timeout time */
- int bytes; /* Length of packet */
- char packet[1453];
- /* Browse data packet */
+ slpsrvurl_t *s, /* New service entry */
+ **head; /* Pointer to head of entry */
- if (!Browsing)
- return;
+ /*
+ * Let the compiler know we won't be using these vars...
+ */
+
+ (void)hslp;
+ (void)lifetime;
/*
- * Compute the update time...
+ * Bail if there was an error
*/
- ut = time(NULL) - BrowseInterval;
- to = time(NULL) - BrowseTimeout;
+ if (errcode != SLP_OK)
+ return (SLP_TRUE);
/*
- * Loop through all of the printers and send local updates as needed...
+ * Grab the head of the list...
*/
- for (p = Printers; p != NULL; p = np)
- {
- np = p->next;
+ head = (slpsrvurl_t**)cookie;
- if (p->type & CUPS_PRINTER_REMOTE)
- {
- /*
- * See if this printer needs to be timed out...
- */
+ /*
+ * Allocate a *temporary* slpsrvurl_t to hold this entry.
+ */
- if (p->browse_time < to)
- {
- LogMessage(L_INFO, "Remote destination \"%s\" has timed out; deleting it...",
- p->name);
- DeletePrinter(p);
- }
- }
- else if (p->browse_time < ut && !(p->type & CUPS_PRINTER_IMPLICIT) &&
- BrowseInterval > 0)
- {
- /*
- * Need to send an update...
- */
+ if ((s = (slpsrvurl_t *)calloc(1, sizeof(slpsrvurl_t))) == NULL)
+ return (SLP_FALSE);
- p->browse_time = time(NULL);
+ /*
+ * Copy the SLP service URL...
+ */
- snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n",
- p->type | CUPS_PRINTER_REMOTE, p->state, p->uri,
- p->location, p->info, p->make_model);
+ strncpy(s->url, srvurl, sizeof(s->url));
- bytes = strlen(packet);
- LogMessage(L_DEBUG2, "SendBrowseList: (%d bytes) %s", bytes, packet);
+ /*
+ * Link the SLP service URL into the head of the list
+ */
- /*
- * Send a packet to each browse address...
- */
+ if (*head)
+ s->next = *head;
- for (i = 0; i < NumBrowsers; i ++)
- if (sendto(BrowseSocket, packet, bytes, 0,
- (struct sockaddr *)Browsers + i, sizeof(Browsers[0])) <= 0)
- {
- LogMessage(L_ERROR, "SendBrowseList: sendto failed for browser %d - %s.",
- i + 1, strerror(errno));
- LogMessage(L_ERROR, "Browsing turned off.");
+ *head = s;
- StopBrowsing();
- Browsing = 0;
- return;
- }
- }
- }
+ return (SLP_TRUE);
}
/*
- * 'StartPolling()' - Start polling servers as needed.
+ * 'UpdateSLPBrowse()' - Get browsing information via SLP.
*/
void
-StartPolling(void)
+UpdateSLPBrowse(void)
{
- int i; /* Looping var */
- dirsvc_poll_t *poll; /* Current polling server */
- int pid; /* New process ID */
- char sport[10]; /* Server port */
- char bport[10]; /* Browser port */
- char interval[10]; /* Poll interval */
+ slpsrvurl_t *s, /* Temporary list of service URLs */
+ *next; /* Next service in list */
+ printer_t p; /* Printer information */
+ const char *uri; /* Pointer to printer URI */
+ char method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
- sprintf(bport, "%d", BrowsePort);
+ LogMessage(L_DEBUG, "UpdateSLPBrowse() Start...");
- if (BrowseInterval)
- sprintf(interval, "%d", BrowseInterval);
- else
- strcpy(interval, "30");
+ /*
+ * Reset the refresh time...
+ */
- for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
- {
- sprintf(sport, "%d", poll->port);
+ BrowseSLPRefresh = time(NULL) + BrowseTimeout - BrowseInterval;
- if ((pid = fork()) == 0)
- {
- /*
- * Child...
- */
+ /*
+ * Poll for remote printers using SLP...
+ */
- if (getuid() == 0)
- {
- /*
- * Running as root, so change to non-priviledged user...
- */
+ s = NULL;
- if (setgid(Group))
- exit(errno);
+ SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "",
+ SrvUrlCallback, &s);
- if (setuid(User))
- exit(errno);
- }
+ /*
+ * Loop through the list of available printers...
+ */
+
+ for (; s; s = next)
+ {
+ /*
+ * Load a printer_t structure with the SLP service attributes...
+ */
+
+ SLPFindAttrs(BrowseSLPHandle, s->url, "", "", AttrCallback, &p);
+
+ /*
+ * Process this printer entry...
+ */
+
+ uri = s->url + SLP_CUPS_SRVLEN + 1;
+ if (strncmp(uri, "http://", 7) == 0 ||
+ strncmp(uri, "ipp://", 6) == 0)
+ {
/*
- * Reset group membership to just the main one we belong to.
+ * Pull the URI apart to see if this is a local or remote printer...
*/
- setgroups(0, NULL);
+ httpSeparate(uri, method, username, host, &port, resource);
+
+ if (strcasecmp(host, ServerName) == 0)
+ continue;
/*
- * Execute the polling daemon...
+ * OK, at least an IPP printer, see if it is a CUPS printer or
+ * class...
*/
- execl(CUPS_SERVERBIN "/daemon/cups-polld", "cups-polld", poll->hostname,
- sport, interval, bport, NULL);
- exit(errno);
- }
- else if (pid < 0)
- {
- LogMessage(L_ERROR, "StartPolling: Unable to fork polling daemon - %s",
- strerror(errno));
- poll->pid = 0;
- break;
- }
- else
- {
- poll->pid = pid;
- LogMessage(L_DEBUG, "StartPolling: Started polling daemon for %s:%d, pid = %d",
- poll->hostname, poll->port, pid);
+ if (strstr(uri, "/printers/") != NULL)
+ ProcessBrowseData(uri, p.type, IPP_PRINTER_IDLE, p.location,
+ p.info, p.make_model);
+ else if (strstr(uri, "/classes/") != NULL)
+ ProcessBrowseData(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE,
+ p.location, p.info, p.make_model);
}
- }
-}
-
-
-/*
- * 'StopPolling()' - Stop polling servers as needed.
- */
-void
-StopPolling(void)
-{
- int i; /* Looping var */
- dirsvc_poll_t *poll; /* Current polling server */
+ /*
+ * Save the "next" pointer and free this listing...
+ */
+ next = s->next;
+ free(s);
+ }
- for (i = 0, poll = Polled; i < NumPolled; i ++, poll ++)
- if (poll->pid)
- kill(poll->pid, SIGTERM);
+ LogMessage(L_DEBUG, "UpdateSLPBrowse() End...");
}
+#endif /* HAVE_LIBSLP */
/*
- * End of "$Id: dirsvc.c,v 1.73.2.2 2001/05/13 18:38:35 mike Exp $".
+ * End of "$Id: dirsvc.c,v 1.73.2.3 2001/12/26 16:52:52 mike Exp $".
*/
diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h
index ad5fe94055..66990ffde4 100644
--- a/scheduler/dirsvc.h
+++ b/scheduler/dirsvc.h
@@ -1,5 +1,5 @@
/*
- * "$Id: dirsvc.h,v 1.12.2.1 2001/04/02 19:51:48 mike Exp $"
+ * "$Id: dirsvc.h,v 1.12.2.2 2001/12/26 16:52:52 mike Exp $"
*
* Directory services definitions for the Common UNIX Printing System
* (CUPS) scheduler.
@@ -23,6 +23,25 @@
* WWW: http://www.cups.org
*/
+/*
+ * Include necessary headers...
+ */
+
+#ifdef HAVE_LIBSLP
+# include
+#endif /* HAVE_LIBSLP */
+
+
+/*
+ * Browse protocols...
+ */
+
+#define BROWSE_CUPS 1 /* CUPS */
+#define BROWSE_SLP 2 /* SLPv2 */
+#define BROWSE_LDAP 4 /* LDAP (not supported yet) */
+#define BROWSE_ALL 7 /* All protocols */
+
+
/*
* Relay structure...
*/
@@ -52,6 +71,8 @@ typedef struct
VAR int Browsing VALUE(TRUE),
/* Whether or not browsing is enabled */
+ BrowseProtocols VALUE(BROWSE_ALL),
+ /* Protocols to support */
BrowseShortNames VALUE(TRUE),
/* Short names for remote printers? */
BrowseSocket VALUE(-1),
@@ -77,20 +98,32 @@ VAR int NumPolled VALUE(0);
VAR dirsvc_poll_t Polled[MAX_BROWSERS];
/* Polled servers */
+#ifdef HAVE_LIBSLP
+VAR SLPHandle BrowseSLPHandle VALUE(NULL);
+ /* SLP API handle */
+VAR time_t BrowseSLPRefresh VALUE(0);
+ /* Next SLP refresh time */
+#endif /* HAVE_LIBSLP */
+
/*
* Prototypes...
*/
-extern void StartBrowsing(void);
-extern void StopBrowsing(void);
-extern void UpdateBrowseList(void);
+extern void ProcessBrowseData(const char *uri, cups_ptype_t type,
+ ipp_pstate_t state, const char *location,
+ const char *info, const char *make_model);
extern void SendBrowseList(void);
-
+extern void SendCUPSBrowse(printer_t *p);
+extern void SendSLPBrowse(printer_t *p);
+extern void StartBrowsing(void);
extern void StartPolling(void);
+extern void StopBrowsing(void);
extern void StopPolling(void);
+extern void UpdateCUPSBrowse(void);
+extern void UpdateSLPBrowse(void);
/*
- * End of "$Id: dirsvc.h,v 1.12.2.1 2001/04/02 19:51:48 mike Exp $".
+ * End of "$Id: dirsvc.h,v 1.12.2.2 2001/12/26 16:52:52 mike Exp $".
*/
diff --git a/scheduler/ipp.c b/scheduler/ipp.c
index cecd041b2c..767d38a37b 100644
--- a/scheduler/ipp.c
+++ b/scheduler/ipp.c
@@ -1,5 +1,5 @@
/*
- * "$Id: ipp.c,v 1.127.2.2 2001/05/13 18:38:35 mike Exp $"
+ * "$Id: ipp.c,v 1.127.2.3 2001/12/26 16:52:53 mike Exp $"
*
* IPP routines for the Common UNIX Printing System (CUPS) scheduler.
*
@@ -53,7 +53,7 @@
* get_printer_attrs() - Get printer attributes.
* get_printers() - Get a list of printers.
* hold_job() - Hold a print job.
- * move_job() - Move a job.
+ * move_job() - Move a job to a new destination.
* print_job() - Print a file to a printer or class.
* reject_jobs() - Reject print jobs to a printer.
* release_job() - Release a held print job.
@@ -94,7 +94,8 @@ static void add_queued_job_count(client_t *con, printer_t *p);
static void cancel_all_jobs(client_t *con, ipp_attribute_t *uri);
static void cancel_job(client_t *con, ipp_attribute_t *uri);
static int check_quotas(client_t *con, printer_t *p);
-static void copy_attribute(ipp_t *to, ipp_attribute_t *attr);
+static void copy_attribute(ipp_t *to, ipp_attribute_t *attr,
+ int quickcopy);
static void copy_attrs(ipp_t *to, ipp_t *from, ipp_attribute_t *req,
ipp_tag_t group);
static int copy_banner(client_t *con, job_t *job, const char *name);
@@ -606,17 +607,22 @@ add_class(client_t *con, /* I - Client connection */
else if (pclass->type & CUPS_PRINTER_IMPLICIT)
{
/*
- * Rename the implicit class to "AnyClass"...
+ * Rename the implicit class to "AnyClass" or remove it...
*/
- snprintf(pclass->name, sizeof(pclass->name), "Any%s", resource + 10);
- SortPrinters();
+ if (ImplicitAnyClasses)
+ {
+ snprintf(pclass->name, sizeof(pclass->name), "Any%s", resource + 9);
+ SortPrinters();
+ }
+ else
+ DeletePrinter(pclass);
/*
* Add the class as a new local class...
*/
- pclass = AddClass(resource + 10);
+ pclass = AddClass(resource + 9);
modify = 0;
}
else if (pclass->type & CUPS_PRINTER_REMOTE)
@@ -626,7 +632,7 @@ add_class(client_t *con, /* I - Client connection */
*/
DeletePrinterFilters(pclass);
- snprintf(pclass->name, sizeof(pclass->name), "%s@%s", resource + 10,
+ snprintf(pclass->name, sizeof(pclass->name), "%s@%s", resource + 9,
pclass->hostname);
SetPrinterAttrs(pclass);
SortPrinters();
@@ -635,7 +641,7 @@ add_class(client_t *con, /* I - Client connection */
* Add the class as a new local class...
*/
- pclass = AddClass(resource + 10);
+ pclass = AddClass(resource + 9);
modify = 0;
}
else
@@ -657,12 +663,6 @@ add_class(client_t *con, /* I - Client connection */
pclass->info[sizeof(pclass->info) - 1] = '\0';
}
- if ((attr = ippFindAttribute(con->request, "printer-more-info", IPP_TAG_URI)) != NULL)
- {
- strncpy(pclass->more_info, attr->values[0].string.text, sizeof(pclass->more_info) - 1);
- pclass->more_info[sizeof(pclass->more_info) - 1] = '\0';
- }
-
if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL)
{
LogMessage(L_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)",
@@ -695,7 +695,8 @@ add_class(client_t *con, /* I - Client connection */
sizeof(pclass->state_message) - 1);
pclass->state_message[sizeof(pclass->state_message) - 1] = '\0';
}
- if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL)
+ if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL &&
+ !Classification[0])
{
strncpy(pclass->job_sheets[0], attr->values[0].string.text,
sizeof(pclass->job_sheets[0]) - 1);
@@ -704,24 +705,6 @@ add_class(client_t *con, /* I - Client connection */
sizeof(pclass->job_sheets[1]) - 1);
else
strcpy(pclass->job_sheets[1], "none");
-
- /*
- * Enforce classification level if set...
- */
-
- if (Classification[0])
- {
- if (strcmp(pclass->job_sheets[0], Classification) != 0 &&
- strcmp(pclass->job_sheets[1], Classification) != 0)
- {
- /*
- * Force the leading banner to have the classification on it...
- */
-
- strcpy(pclass->job_sheets[0], Classification);
- }
- }
-
}
if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed",
IPP_TAG_ZERO)) != NULL)
@@ -1037,11 +1020,16 @@ add_printer(client_t *con, /* I - Client connection */
else if (printer->type & CUPS_PRINTER_IMPLICIT)
{
/*
- * Rename the implicit printer to "AnyPrinter"...
+ * Rename the implicit printer to "AnyPrinter" or delete it...
*/
- snprintf(printer->name, sizeof(printer->name), "Any%s", resource + 10);
- SortPrinters();
+ if (ImplicitAnyClasses)
+ {
+ snprintf(printer->name, sizeof(printer->name), "Any%s", resource + 10);
+ SortPrinters();
+ }
+ else
+ DeletePrinter(printer);
/*
* Add the printer as a new local printer...
@@ -1088,14 +1076,47 @@ add_printer(client_t *con, /* I - Client connection */
printer->info[sizeof(printer->info) - 1] = '\0';
}
- if ((attr = ippFindAttribute(con->request, "printer-more-info", IPP_TAG_URI)) != NULL)
- {
- strncpy(printer->more_info, attr->values[0].string.text, sizeof(printer->more_info) - 1);
- printer->more_info[sizeof(printer->more_info) - 1] = '\0';
- }
-
if ((attr = ippFindAttribute(con->request, "device-uri", IPP_TAG_URI)) != NULL)
{
+ ipp_attribute_t *device; /* Current device */
+ int methodlen; /* Length of method string */
+
+
+ /*
+ * Do we have a valid device URI?
+ */
+
+ httpSeparate(attr->values[0].string.text, method, username, host,
+ &port, resource);
+ methodlen = strlen(method);
+
+ if (strcmp(method, "file") != 0)
+ {
+ /*
+ * See if the backend is listed as a device...
+ */
+
+ for (device = ippFindAttribute(Devices, "device-uri", IPP_TAG_URI);
+ device != NULL;
+ device = ippFindNextAttribute(Devices, "device-uri", IPP_TAG_URI))
+ if (strncmp(method, device->values[0].string.text, methodlen) == 0 &&
+ (device->values[0].string.text[methodlen] == ':' ||
+ device->values[0].string.text[methodlen] == '\0'))
+ break;
+
+ if (device == NULL)
+ {
+ /*
+ * Could not find device in list!
+ */
+
+ LogMessage(L_ERROR, "add_printer: bad device-uri attribute \'%s\'!",
+ attr->values[0].string.text);
+ send_ipp_error(con, IPP_NOT_POSSIBLE);
+ return;
+ }
+ }
+
LogMessage(L_INFO, "Setting %s device-uri to \"%s\" (was \"%s\".)",
printer->name, attr->values[0].string.text, printer->device_uri);
@@ -1136,7 +1157,8 @@ add_printer(client_t *con, /* I - Client connection */
sizeof(printer->state_message) - 1);
printer->state_message[sizeof(printer->state_message) - 1] = '\0';
}
- if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL)
+ if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL &&
+ !Classification[0])
{
strncpy(printer->job_sheets[0], attr->values[0].string.text,
sizeof(printer->job_sheets[0]) - 1);
@@ -1145,23 +1167,6 @@ add_printer(client_t *con, /* I - Client connection */
sizeof(printer->job_sheets[1]) - 1);
else
strcpy(printer->job_sheets[1], "none");
-
- /*
- * Force classification if necessary...
- */
-
- if (Classification[0])
- {
- if (strcmp(printer->job_sheets[0], Classification) != 0 &&
- strcmp(printer->job_sheets[1], Classification) != 0)
- {
- /*
- * Force the leading banner to have the classification on it...
- */
-
- strcpy(printer->job_sheets[0], Classification);
- }
- }
}
if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed",
IPP_TAG_ZERO)) != NULL)
@@ -1169,7 +1174,9 @@ add_printer(client_t *con, /* I - Client connection */
FreePrinterUsers(printer);
printer->deny_users = 0;
- if (attr->value_tag == IPP_TAG_NAME)
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "all") != 0))
for (i = 0; i < attr->num_values; i ++)
AddPrinterUser(printer, attr->values[i].string.text);
}
@@ -1179,7 +1186,9 @@ add_printer(client_t *con, /* I - Client connection */
FreePrinterUsers(printer);
printer->deny_users = 1;
- if (attr->value_tag == IPP_TAG_NAME)
+ if (attr->value_tag == IPP_TAG_NAME &&
+ (attr->num_values > 1 ||
+ strcmp(attr->values[0].string.text, "none") != 0))
for (i = 0; i < attr->num_values; i ++)
AddPrinterUser(printer, attr->values[i].string.text);
}
@@ -1219,17 +1228,36 @@ add_printer(client_t *con, /* I - Client connection */
srcfile[sizeof(srcfile) - 1] = '\0';
}
else if ((attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL)
- snprintf(srcfile, sizeof(srcfile), "%s/model/%s", DataDir,
- attr->values[0].string.text);
+ {
+ if (strcmp(attr->values[0].string.text, "raw") == 0)
+ strcpy(srcfile, "raw");
+ else
+ snprintf(srcfile, sizeof(srcfile), "%s/model/%s", DataDir,
+ attr->values[0].string.text);
+ }
else
srcfile[0] = '\0';
LogMessage(L_DEBUG, "add_printer: srcfile = \"%s\"", srcfile);
+ if (strcmp(srcfile, "raw") == 0)
+ {
+ /*
+ * Raw driver, remove any existing PPD or interface script files.
+ */
+
+ snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot,
+ printer->name);
+ unlink(dstfile);
+
+ snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot,
+ printer->name);
+ unlink(dstfile);
+ }
#ifdef HAVE_LIBZ
- if (srcfile[0] && (fp = gzopen(srcfile, "rb")) != NULL)
+ else if (srcfile[0] && (fp = gzopen(srcfile, "rb")) != NULL)
#else
- if (srcfile[0] && (fp = fopen(srcfile, "rb")) != NULL)
+ else if (srcfile[0] && (fp = fopen(srcfile, "rb")) != NULL)
#endif /* HAVE_LIBZ */
{
/*
@@ -1771,7 +1799,7 @@ check_quotas(client_t *con, /* I - Client connection */
if (p->num_users)
{
for (i = 0; i < p->num_users; i ++)
- if (strcmp(username, p->users[i]) == 0)
+ if (strcasecmp(username, p->users[i]) == 0)
break;
if ((i < p->num_users) == p->deny_users)
@@ -1818,7 +1846,8 @@ check_quotas(client_t *con, /* I - Client connection */
static void
copy_attribute(ipp_t *to, /* O - Destination request/response */
- ipp_attribute_t *attr) /* I - Attribute to copy */
+ ipp_attribute_t *attr, /* I - Attribute to copy */
+ int quickcopy)/* I - Do a quick copy? */
{
int i; /* Looping var */
ipp_attribute_t *toattr; /* Destination attribute */
@@ -1827,7 +1856,7 @@ copy_attribute(ipp_t *to, /* O - Destination request/response */
LogMessage(L_DEBUG2, "copy_attribute(%p, %s)\n", to,
attr->name ? attr->name : "(null)");
- switch (attr->value_tag)
+ switch (attr->value_tag & ~IPP_TAG_COPY)
{
case IPP_TAG_ZERO :
ippAddSeparator(to);
@@ -1860,12 +1889,19 @@ copy_attribute(ipp_t *to, /* O - Destination request/response */
case IPP_TAG_LANGUAGE :
case IPP_TAG_MIMETYPE :
toattr = ippAddStrings(to, attr->group_tag,
- (ipp_tag_t)(attr->value_tag | IPP_TAG_COPY),
- attr->name, attr->num_values, NULL,
- NULL);
+ (ipp_tag_t)(attr->value_tag | quickcopy),
+ attr->name, attr->num_values, NULL, NULL);
- for (i = 0; i < attr->num_values; i ++)
- toattr->values[i].string.text = attr->values[i].string.text;
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ else
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ toattr->values[i].string.text = strdup(attr->values[i].string.text);
+ }
break;
case IPP_TAG_DATE :
@@ -1900,13 +1936,30 @@ copy_attribute(ipp_t *to, /* O - Destination request/response */
case IPP_TAG_TEXTLANG :
case IPP_TAG_NAMELANG :
toattr = ippAddStrings(to, attr->group_tag,
- (ipp_tag_t)(attr->value_tag | IPP_TAG_COPY),
+ (ipp_tag_t)(attr->value_tag | quickcopy),
attr->name, attr->num_values, NULL, NULL);
- for (i = 0; i < attr->num_values; i ++)
+ if (quickcopy)
+ {
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ toattr->values[i].string.charset = attr->values[i].string.charset;
+ toattr->values[i].string.text = attr->values[i].string.text;
+ }
+ }
+ else
{
- toattr->values[i].string.charset = attr->values[i].string.charset;
- toattr->values[i].string.text = attr->values[i].string.text;
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (!i)
+ toattr->values[i].string.charset =
+ strdup(attr->values[i].string.charset);
+ else
+ toattr->values[i].string.charset =
+ toattr->values[0].string.charset;
+
+ toattr->values[i].string.text = strdup(attr->values[i].string.text);
+ }
}
break;
@@ -1975,7 +2028,7 @@ copy_attrs(ipp_t *to, /* I - Destination request */
continue;
}
- copy_attribute(to, fromattr);
+ copy_attribute(to, fromattr, IPP_TAG_COPY);
}
}
@@ -2198,7 +2251,8 @@ create_job(client_t *con, /* I - Client connection */
if (attr == NULL)
attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
"job-hold-until", NULL, "no-hold");
- if (attr != NULL && strcmp(attr->values[0].string.text, "no-hold") != 0)
+ if (attr != NULL && strcmp(attr->values[0].string.text, "no-hold") != 0 &&
+ !(printer->type & CUPS_PRINTER_REMOTE))
{
/*
* Hold job until specified time...
@@ -2219,6 +2273,9 @@ create_job(client_t *con, /* I - Client connection */
if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) == NULL)
{
+ LogMessage(L_DEBUG, "Adding default job-sheets values \"%s,%s\"...",
+ printer->job_sheets[0], printer->job_sheets[1]);
+
attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
2, NULL, NULL);
attr->values[0].string.text = strdup(printer->job_sheets[0]);
@@ -2233,9 +2290,35 @@ create_job(client_t *con, /* I - Client connection */
if (Classification[0])
{
- if (strcmp(attr->values[0].string.text, Classification) != 0 &&
- (attr->num_values == 1 ||
- strcmp(attr->values[1].string.text, Classification) != 0))
+ if (ClassifyOverride)
+ {
+ if (strcmp(attr->values[0].string.text, "none") == 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, "none") == 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ else if (attr->num_values == 2 &&
+ strcmp(attr->values[0].string.text, attr->values[1].string.text) != 0 &&
+ strcmp(attr->values[0].string.text, "none") != 0 &&
+ strcmp(attr->values[1].string.text, "none") != 0)
+ {
+ /*
+ * Can't put two different security markings on the same document!
+ */
+
+ free(attr->values[1].string.text);
+ attr->values[1].string.text = strdup(attr->values[0].string.text);
+ }
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) != 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, Classification) != 0))
{
/*
* Force the leading banner to have the classification on it...
@@ -2254,6 +2337,8 @@ create_job(client_t *con, /* I - Client connection */
UpdateQuota(printer, job->username, 0, kbytes);
}
+ else if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
+ job->sheets = attr;
/*
* Save and log the job...
@@ -2345,7 +2430,49 @@ copy_banner(client_t *con, /* I - Client connection */
fchmod(fileno(out), 0640);
fchown(fileno(out), User, Group);
- if ((in = fopen(banner->filename, "r")) == NULL)
+ if (con->language)
+ {
+ /*
+ * Try the localized banner file under the subdirectory...
+ */
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
+ con->language->language, name);
+
+ if (access(filename, 0) && con->language->language[2])
+ {
+ /*
+ * Wasn't able to find "ll_CC" locale file; try the non-national
+ * localization banner directory.
+ */
+
+ attrname[0] = con->language->language[0];
+ attrname[1] = con->language->language[1];
+ attrname[2] = '\0';
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir,
+ attrname, name);
+ }
+
+ if (access(filename, 0))
+ {
+ /*
+ * Use the non-localized banner file.
+ */
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
+ }
+ }
+ else
+ {
+ /*
+ * Use the non-localized banner file.
+ */
+
+ snprintf(filename, sizeof(filename), "%s/banners/%s", DataDir, name);
+ }
+
+ if ((in = fopen(filename, "r")) == NULL)
{
fclose(out);
unlink(filename);
@@ -2367,35 +2494,60 @@ copy_banner(client_t *con, /* I - Client connection */
*/
for (s = attrname; (ch = getc(in)) != EOF;)
- if (ch == '}' || isspace(ch))
+ if (!isalpha(ch) && ch != '-' && ch != '?')
break;
else if (s < (attrname + sizeof(attrname) - 1))
*s++ = ch;
+ else
+ break;
+
+ *s = '\0';
- if (isspace(ch) && s == attrname)
+ if (ch != '}')
{
/*
- * Ignore { followed by whitespace...
+ * Ignore { followed by stuff that is not an attribute name...
*/
putc('{', out);
+ fputs(attrname, out);
putc(ch, out);
continue;
}
- *s = '\0';
-
/*
* See if it is defined...
*/
- if (strcmp(attrname, "printer-name") == 0)
+ if (attrname[0] == '?')
+ s = attrname + 1;
+ else
+ s = attrname;
+
+ if (strcmp(s, "printer-name") == 0)
{
fputs(job->dest, out);
continue;
}
- else if ((attr = ippFindAttribute(job->attrs, attrname, IPP_TAG_ZERO)) == NULL)
- continue; /* Nope */
+ else if ((attr = ippFindAttribute(job->attrs, s, IPP_TAG_ZERO)) == NULL)
+ {
+ /*
+ * See if we have a leading question mark...
+ */
+
+ if (attrname[0] != '?')
+ {
+ /*
+ * Nope, write to file as-is; probably a PostScript procedure...
+ */
+
+ putc('{', out);
+ fputs(attrname, out);
+ putc('}', out);
+ }
+
+ continue;
+ }
/*
* Output value(s)...
@@ -2623,11 +2775,15 @@ delete_printer(client_t *con, /* I - Client connection */
printer = FindPrinter(dest);
/*
- * Remove any old PPD or script files...
+ * Remove old jobs...
*/
CancelJobs(dest);
+ /*
+ * Remove any old PPD or script files...
+ */
+
snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, dest);
unlink(filename);
@@ -3130,6 +3286,10 @@ get_printers(client_t *con, /* I - Client connection */
int printer_type, /* printer-type attribute */
printer_mask; /* printer-type-mask attribute */
char *location; /* Location string */
+ char name[IPP_MAX_NAME],
+ /* Printer name */
+ *nameptr; /* Pointer into name */
+ printer_t *iclass; /* Implicit class */
LogMessage(L_DEBUG2, "get_printers(%d, %x)\n", con->http.fd, type);
@@ -3178,6 +3338,45 @@ get_printers(client_t *con, /* I - Client connection */
(printer->type & printer_mask) == printer_type &&
(location == NULL || strcasecmp(printer->location, location) == 0))
{
+ /*
+ * If HideImplicitMembers is enabled, see if this printer or class
+ * is a member of an implicit class...
+ */
+
+ if (ImplicitClasses && HideImplicitMembers &&
+ (printer->type & CUPS_PRINTER_REMOTE))
+ {
+ /*
+ * Make a copy of the printer name...
+ *
+ * Note: name and printer->name are both IPP_MAX_NAME characters
+ * in size, so strcpy() is safe...
+ */
+
+ strcpy(name, printer->name);
+
+ if ((nameptr = strchr(name, '@')) != NULL)
+ {
+ /*
+ * Strip trailing @server...
+ */
+
+ *nameptr = '\0';
+
+ /*
+ * Find the core printer, if any...
+ */
+
+ if ((iclass = FindPrinter(name)) != NULL &&
+ (iclass->type & CUPS_PRINTER_IMPLICIT))
+ continue;
+ }
+ }
+
+ /*
+ * Add the group separator as needed...
+ */
+
if (count > 0)
ippAddSeparator(con->response);
@@ -3372,7 +3571,7 @@ hold_job(client_t *con, /* I - Client connection */
/*
- * 'move_job()' - Set job attributes.
+ * 'move_job()' - Move a job to a new destination.
*/
static void
@@ -3869,7 +4068,8 @@ print_job(client_t *con, /* I - Client connection */
attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
"job-hold-until", NULL, "no-hold");
- if (attr != NULL && strcmp(attr->values[0].string.text, "no-hold") != 0)
+ if (attr != NULL && strcmp(attr->values[0].string.text, "no-hold") != 0 &&
+ !(printer->type & CUPS_PRINTER_REMOTE))
{
/*
* Hold job until specified time...
@@ -3887,6 +4087,9 @@ print_job(client_t *con, /* I - Client connection */
if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) == NULL)
{
+ LogMessage(L_DEBUG, "Adding default job-sheets values \"%s,%s\"...",
+ printer->job_sheets[0], printer->job_sheets[1]);
+
attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets",
2, NULL, NULL);
attr->values[0].string.text = strdup(printer->job_sheets[0]);
@@ -3901,9 +4104,35 @@ print_job(client_t *con, /* I - Client connection */
if (Classification[0])
{
- if (strcmp(attr->values[0].string.text, Classification) != 0 &&
- (attr->num_values == 1 ||
- strcmp(attr->values[1].string.text, Classification) != 0))
+ if (ClassifyOverride)
+ {
+ if (strcmp(attr->values[0].string.text, "none") == 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, "none") == 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ else if (attr->num_values == 2 &&
+ strcmp(attr->values[0].string.text, attr->values[1].string.text) != 0 &&
+ strcmp(attr->values[0].string.text, "none") != 0 &&
+ strcmp(attr->values[1].string.text, "none") != 0)
+ {
+ /*
+ * Can't put two different security markings on the same document!
+ */
+
+ free(attr->values[1].string.text);
+ attr->values[1].string.text = strdup(attr->values[0].string.text);
+ }
+ }
+ else if (strcmp(attr->values[0].string.text, Classification) != 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, Classification) != 0))
{
/*
* Force the leading banner to have the classification on it...
@@ -3922,6 +4151,8 @@ print_job(client_t *con, /* I - Client connection */
UpdateQuota(printer, job->username, 0, kbytes);
}
+ else if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
+ job->sheets = attr;
/*
* Add the job file...
@@ -4981,7 +5212,7 @@ set_job_attrs(client_t *con, /* I - Client connection */
* Then copy the attribute...
*/
- copy_attribute(job->attrs, attr);
+ copy_attribute(job->attrs, attr, 0);
/*
* See if the job-name or job-hold-until is being changed.
@@ -5027,7 +5258,7 @@ set_job_attrs(client_t *con, /* I - Client connection */
* Add new option by copying it...
*/
- copy_attribute(job->attrs, attr);
+ copy_attribute(job->attrs, attr, 0);
}
}
@@ -5356,7 +5587,7 @@ validate_user(client_t *con, /* I - Client connection */
char *username, /* O - Authenticated username */
int userlen) /* I - Length of username */
{
- int i; /* Looping var */
+ int i, j; /* Looping vars */
ipp_attribute_t *attr; /* requesting-user-name attribute */
struct passwd *user; /* User info */
struct group *group; /* System group info */
@@ -5389,7 +5620,7 @@ validate_user(client_t *con, /* I - Client connection */
* Check the username against the owner...
*/
- if (strcmp(username, owner) != 0 && strcmp(username, "root") != 0)
+ if (strcasecmp(username, owner) != 0 && strcasecmp(username, "root") != 0)
{
/*
* Not the owner or root; check to see if the user is a member of the
@@ -5399,20 +5630,26 @@ validate_user(client_t *con, /* I - Client connection */
user = getpwnam(username);
endpwent();
- group = getgrnam(SystemGroup);
- endgrent();
-
- if (group != NULL)
+ for (i = 0, j = 0, group = NULL; i < NumSystemGroups; i ++)
{
- for (i = 0; group->gr_mem[i]; i ++)
- if (strcmp(username, group->gr_mem[i]) == 0)
+ group = getgrnam(SystemGroups[i]);
+ endgrent();
+
+ if (group != NULL)
+ {
+ for (j = 0; group->gr_mem[j]; j ++)
+ if (strcasecmp(username, group->gr_mem[j]) == 0)
+ break;
+
+ if (group->gr_mem[j])
break;
+ }
+ else
+ j = 0;
}
- else
- i = 0;
if (user == NULL || group == NULL ||
- (group->gr_mem[i] == NULL && group->gr_gid != user->pw_gid))
+ (group->gr_mem[j] == NULL && group->gr_gid != user->pw_gid))
{
/*
* Username not found, group not found, or user is not part of the
@@ -5428,5 +5665,5 @@ validate_user(client_t *con, /* I - Client connection */
/*
- * End of "$Id: ipp.c,v 1.127.2.2 2001/05/13 18:38:35 mike Exp $".
+ * End of "$Id: ipp.c,v 1.127.2.3 2001/12/26 16:52:53 mike Exp $".
*/
diff --git a/scheduler/job.c b/scheduler/job.c
index e485662ff2..33602ccf06 100644
--- a/scheduler/job.c
+++ b/scheduler/job.c
@@ -1,5 +1,5 @@
/*
- * "$Id: job.c,v 1.124.2.2 2001/05/13 18:38:36 mike Exp $"
+ * "$Id: job.c,v 1.124.2.3 2001/12/26 16:52:54 mike Exp $"
*
* Job management routines for the Common UNIX Printing System (CUPS).
*
@@ -282,8 +282,10 @@ CheckJobs(void)
if (pclass->type & CUPS_PRINTER_REMOTE)
printer = pclass;
- else
+ else if (pclass->state != IPP_PRINTER_STOPPED)
printer = FindAvailablePrinter(current->dest);
+ else
+ printer = NULL;
}
else
printer = FindPrinter(current->dest);
@@ -294,8 +296,12 @@ CheckJobs(void)
* Handle implicit classes...
*/
- pclass = printer;
- printer = FindAvailablePrinter(current->dest);
+ pclass = printer;
+
+ if (pclass->state != IPP_PRINTER_STOPPED)
+ printer = FindAvailablePrinter(current->dest);
+ else
+ printer = NULL;
}
if (printer == NULL && pclass == NULL)
@@ -731,8 +737,11 @@ MoveJob(int id, /* I - Job ID */
for (current = Jobs; current != NULL; current = current->next)
if (current->id == id)
{
- if (current->state->values[0].integer == IPP_JOB_PENDING)
- strncpy(current->dest, dest, sizeof(current->dest) - 1);
+ if (current->state->values[0].integer >= IPP_JOB_PROCESSING)
+ break;
+
+ strncpy(current->dest, dest, sizeof(current->dest) - 1);
+ current->dtype = p->type & CUPS_PRINTER_CLASS;
if ((attr = ippFindAttribute(current->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL)
{
@@ -1072,7 +1081,7 @@ StartJob(int id, /* I - Job ID */
path[1024], /* PATH environment variable */
language[255], /* LANG environment variable */
charset[255], /* CHARSET environment variable */
- classification[1024], /* CLASSIFICATION environmeent variable */
+ classification[1024], /* CLASSIFICATION environment variable */
content_type[255],/* CONTENT_TYPE environment variable */
device_uri[1024],/* DEVICE_URI environment variable */
ppd[1024], /* PPD environment variable */
@@ -1141,8 +1150,35 @@ StartJob(int id, /* I - Job ID */
return;
}
- for (i = 0; i < num_filters; i ++)
- current->cost += filters[i].cost;
+ /*
+ * Remove NULL ("-") filters...
+ */
+
+ for (i = 0; i < num_filters;)
+ if (strcmp(filters[i].filter, "-") == 0)
+ {
+ num_filters --;
+ if (i < num_filters)
+ memcpy(filters + i, filters + i + 1,
+ (num_filters - i) * sizeof(mime_filter_t));
+ }
+ else
+ i ++;
+
+ if (num_filters == 0)
+ {
+ free(filters);
+ filters = NULL;
+ }
+ else
+ {
+ /*
+ * Compute filter cost...
+ */
+
+ for (i = 0; i < num_filters; i ++)
+ current->cost += filters[i].cost;
+ }
}
/*
@@ -1188,7 +1224,12 @@ StartJob(int id, /* I - Job ID */
*/
if (current->job_sheets == NULL)
+ {
LogMessage(L_DEBUG, "No job-sheets attribute.");
+ if ((current->job_sheets =
+ ippFindAttribute(current->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
+ LogMessage(L_DEBUG, "... but someone added one without setting job_sheets!");
+ }
else if (current->job_sheets->num_values == 1)
LogMessage(L_DEBUG, "job-sheets=%s",
current->job_sheets->values[0].string.text);
@@ -1421,8 +1462,19 @@ StartJob(int id, /* I - Job ID */
snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir);
snprintf(fontpath, sizeof(fontpath), "CUPS_FONTPATH=%s", FontPath);
if (Classification[0] && !banner_page)
- snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
- Classification);
+ {
+ if ((attr = ippFindAttribute(current->attrs, "job-sheets",
+ IPP_TAG_NAME)) == NULL)
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ Classification);
+ else if (attr->num_values > 1 &&
+ strcmp(attr->values[1].string.text, "none") != 0)
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ attr->values[1].string.text);
+ else
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ attr->values[0].string.text);
+ }
else
classification[0] = '\0';
if (getenv("LD_LIBRARY_PATH") != NULL)
@@ -1929,6 +1981,895 @@ UpdateJob(job_t *job) /* I - Job to check */
}
+/*
+ * 'ipp_read_file()' - Read an IPP request from a file.
+ */
+
+static ipp_state_t /* O - State */
+ipp_read_file(const char *filename, /* I - File to read from */
+ ipp_t *ipp) /* I - Request to read into */
+{
+ int fd; /* File descriptor for file */
+ int n; /* Length of data */
+ unsigned char buffer[8192], /* Data buffer */
+ *bufptr; /* Pointer into buffer */
+ ipp_attribute_t *attr; /* Current attribute */
+ ipp_tag_t tag; /* Current tag */
+
+
+ /*
+ * Open the file if possible...
+ */
+
+ if (filename == NULL || ipp == NULL)
+ return (IPP_ERROR);
+
+ if ((fd = open(filename, O_RDONLY)) == -1)
+ return (IPP_ERROR);
+
+ /*
+ * Read the IPP request...
+ */
+
+ ipp->state = IPP_IDLE;
+
+ switch (ipp->state)
+ {
+ default :
+ break; /* anti-compiler-warning-code */
+
+ case IPP_IDLE :
+ ipp->state ++; /* Avoid common problem... */
+
+ case IPP_HEADER :
+ /*
+ * Get the request header...
+ */
+
+ if ((n = read(fd, buffer, 8)) < 8)
+ {
+ DEBUG_printf(("ipp_read_file: Unable to read header (%d bytes read)!\n", n));
+ close(fd);
+ return (n == 0 ? IPP_IDLE : IPP_ERROR);
+ }
+
+ /*
+ * Verify the major version number...
+ */
+
+ if (buffer[0] != 1)
+ {
+ DEBUG_printf(("ipp_read_file: version number (%d.%d) is bad.\n", buffer[0],
+ buffer[1]));
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Then copy the request header over...
+ */
+
+ ipp->request.any.version[0] = buffer[0];
+ ipp->request.any.version[1] = buffer[1];
+ ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
+ ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
+ buffer[6]) << 8) | buffer[7];
+
+ ipp->state = IPP_ATTRIBUTE;
+ ipp->current = NULL;
+ ipp->curtag = IPP_TAG_ZERO;
+
+ case IPP_ATTRIBUTE :
+ while (read(fd, buffer, 1) > 0)
+ {
+ /*
+ * Read this attribute...
+ */
+
+ tag = (ipp_tag_t)buffer[0];
+
+ if (tag == IPP_TAG_END)
+ {
+ /*
+ * No more attributes left...
+ */
+
+ DEBUG_puts("ipp_read_file: IPP_TAG_END!");
+
+ ipp->state = IPP_DATA;
+ break;
+ }
+ else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
+ {
+ /*
+ * Group tag... Set the current group and continue...
+ */
+
+ if (ipp->curtag == tag)
+ ippAddSeparator(ipp);
+
+ ipp->curtag = tag;
+ ipp->current = NULL;
+ DEBUG_printf(("ipp_read_file: group tag = %x\n", tag));
+ continue;
+ }
+
+ DEBUG_printf(("ipp_read_file: value tag = %x\n", tag));
+
+ /*
+ * Get the name...
+ */
+
+ if (read(fd, buffer, 2) < 2)
+ {
+ DEBUG_puts("ipp_read_file: unable to read name length!");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ n = (buffer[0] << 8) | buffer[1];
+
+ DEBUG_printf(("ipp_read_file: name length = %d\n", n));
+
+ if (n == 0)
+ {
+ /*
+ * More values for current attribute...
+ */
+
+ if (ipp->current == NULL)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr = ipp->current;
+
+ /*
+ * Finally, reallocate the attribute array as needed...
+ */
+
+ if ((attr->num_values % IPP_MAX_VALUES) == 0)
+ {
+ ipp_attribute_t *temp, /* Pointer to new buffer */
+ *ptr; /* Pointer in attribute list */
+
+
+ /*
+ * Reallocate memory...
+ */
+
+ if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
+ (attr->num_values + IPP_MAX_VALUES - 1) *
+ sizeof(ipp_value_t))) == NULL)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ /*
+ * Reset pointers in the list...
+ */
+
+ for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next);
+
+ if (ptr)
+ ptr->next = temp;
+ else
+ ipp->attrs = temp;
+
+ attr = ipp->current = ipp->last = temp;
+ }
+ }
+ else
+ {
+ /*
+ * New attribute; read the name and add it...
+ */
+
+ if (read(fd, buffer, n) < n)
+ {
+ DEBUG_puts("ipp_read_file: unable to read name!");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ buffer[n] = '\0';
+ DEBUG_printf(("ipp_read_file: name = \'%s\'\n", buffer));
+
+ attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
+
+ attr->group_tag = ipp->curtag;
+ attr->value_tag = tag;
+ attr->name = strdup((char *)buffer);
+ attr->num_values = 0;
+ }
+
+ if (read(fd, buffer, 2) < 2)
+ {
+ DEBUG_puts("ipp_read_file: unable to read value length!");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ n = (buffer[0] << 8) | buffer[1];
+ DEBUG_printf(("ipp_read_file: value length = %d\n", n));
+
+ switch (tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (read(fd, buffer, 4) < 4)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+
+ attr->values[attr->num_values].integer = n;
+ break;
+ case IPP_TAG_BOOLEAN :
+ if (read(fd, buffer, 1) < 1)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr->values[attr->num_values].boolean = buffer[0];
+ break;
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_STRING :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ if (read(fd, buffer, n) < n)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ buffer[n] = '\0';
+ DEBUG_printf(("ipp_read_file: value = \'%s\'\n", buffer));
+
+ attr->values[attr->num_values].string.text = strdup((char *)buffer);
+ break;
+ case IPP_TAG_DATE :
+ if (read(fd, buffer, 11) < 11)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ memcpy(attr->values[attr->num_values].date, buffer, 11);
+ break;
+ case IPP_TAG_RESOLUTION :
+ if (read(fd, buffer, 9) < 9)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr->values[attr->num_values].resolution.xres =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ attr->values[attr->num_values].resolution.yres =
+ (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
+ buffer[7];
+ attr->values[attr->num_values].resolution.units =
+ (ipp_res_t)buffer[8];
+ break;
+ case IPP_TAG_RANGE :
+ if (read(fd, buffer, 8) < 8)
+ {
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ attr->values[attr->num_values].range.lower =
+ (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
+ buffer[3];
+ attr->values[attr->num_values].range.upper =
+ (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
+ buffer[7];
+ break;
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ if (read(fd, buffer, n) < n)
+ return (IPP_ERROR);
+
+ bufptr = buffer;
+
+ /*
+ * text-with-language and name-with-language are composite
+ * values:
+ *
+ * charset-length
+ * charset
+ * text-length
+ * text
+ */
+
+ n = (bufptr[0] << 8) | bufptr[1];
+
+ attr->values[attr->num_values].string.charset = calloc(n + 1, 1);
+
+ memcpy(attr->values[attr->num_values].string.charset,
+ bufptr + 2, n);
+
+ bufptr += 2 + n;
+ n = (bufptr[0] << 8) | bufptr[1];
+
+ attr->values[attr->num_values].string.text = calloc(n + 1, 1);
+
+ memcpy(attr->values[attr->num_values].string.text,
+ bufptr + 2, n);
+
+ break;
+
+ default : /* Other unsupported values */
+ attr->values[attr->num_values].unknown.length = n;
+ if (n > 0)
+ {
+ attr->values[attr->num_values].unknown.data = malloc(n);
+ if (read(fd, attr->values[attr->num_values].unknown.data, n) < n)
+ return (IPP_ERROR);
+ }
+ else
+ attr->values[attr->num_values].unknown.data = NULL;
+ break;
+ }
+
+ attr->num_values ++;
+ }
+ break;
+
+ case IPP_DATA :
+ break;
+ }
+
+ /*
+ * Close the file and return...
+ */
+
+ close(fd);
+
+ return (ipp->state);
+}
+
+
+/*
+ * 'ipp_write_file()' - Write an IPP request to a file.
+ */
+
+static ipp_state_t /* O - State */
+ipp_write_file(const char *filename, /* I - File to write to */
+ ipp_t *ipp) /* I - Request to write */
+{
+ int fd; /* File descriptor */
+ int i; /* Looping var */
+ int n; /* Length of data */
+ unsigned char buffer[8192], /* Data buffer */
+ *bufptr; /* Pointer into buffer */
+ ipp_attribute_t *attr; /* Current attribute */
+
+
+ /*
+ * Open the file if possible...
+ */
+
+ if (filename == NULL || ipp == NULL)
+ return (IPP_ERROR);
+
+ if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) == -1)
+ return (IPP_ERROR);
+
+ fchmod(fd, 0600);
+ fchown(fd, User, Group);
+
+ /*
+ * Write the IPP request...
+ */
+
+ ipp->state = IPP_IDLE;
+
+ switch (ipp->state)
+ {
+ default :
+ break; /* anti-compiler-warning-code */
+
+ case IPP_IDLE :
+ ipp->state ++; /* Avoid common problem... */
+
+ case IPP_HEADER :
+ /*
+ * Send the request header...
+ */
+
+ bufptr = buffer;
+
+ *bufptr++ = ipp->request.any.version[0];
+ *bufptr++ = ipp->request.any.version[1];
+ *bufptr++ = ipp->request.any.op_status >> 8;
+ *bufptr++ = ipp->request.any.op_status;
+ *bufptr++ = ipp->request.any.request_id >> 24;
+ *bufptr++ = ipp->request.any.request_id >> 16;
+ *bufptr++ = ipp->request.any.request_id >> 8;
+ *bufptr++ = ipp->request.any.request_id;
+
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP header...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ ipp->state = IPP_ATTRIBUTE;
+ ipp->current = ipp->attrs;
+ ipp->curtag = IPP_TAG_ZERO;
+
+ case IPP_ATTRIBUTE :
+ while (ipp->current != NULL)
+ {
+ /*
+ * Write this attribute...
+ */
+
+ bufptr = buffer;
+ attr = ipp->current;
+
+ ipp->current = ipp->current->next;
+
+ if (ipp->curtag != attr->group_tag)
+ {
+ /*
+ * Send a group operation tag...
+ */
+
+ ipp->curtag = attr->group_tag;
+
+ if (attr->group_tag == IPP_TAG_ZERO)
+ continue;
+
+ DEBUG_printf(("ipp_write_file: wrote group tag = %x\n", attr->group_tag));
+ *bufptr++ = attr->group_tag;
+ }
+
+ if ((n = strlen(attr->name)) > (sizeof(buffer) - 3))
+ return (IPP_ERROR);
+
+ DEBUG_printf(("ipp_write_file: writing value tag = %x\n", attr->value_tag));
+ DEBUG_printf(("ipp_write_file: writing name = %d, \'%s\'\n", n, attr->name));
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+ memcpy(bufptr, attr->name, n);
+ bufptr += n;
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 9)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 4;
+ *bufptr++ = attr->values[i].integer >> 24;
+ *bufptr++ = attr->values[i].integer >> 16;
+ *bufptr++ = attr->values[i].integer >> 8;
+ *bufptr++ = attr->values[i].integer;
+ }
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 6)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 1;
+ *bufptr++ = attr->values[i].boolean;
+ }
+ break;
+
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_STRING :
+ case IPP_TAG_URI :
+ case IPP_TAG_URISCHEME :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ DEBUG_printf(("ipp_write_file: writing value tag = %x\n",
+ attr->value_tag));
+ DEBUG_printf(("ipp_write_file: writing name = 0, \'\'\n"));
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = strlen(attr->values[i].string.text);
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ DEBUG_printf(("ipp_write_file: writing string = %d, \'%s\'\n", n,
+ attr->values[i].string.text));
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+ memcpy(bufptr, attr->values[i].string.text, n);
+ bufptr += n;
+ }
+ break;
+
+ case IPP_TAG_DATE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 16)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 11;
+ memcpy(bufptr, attr->values[i].date, 11);
+ bufptr += 11;
+ }
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 14)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 9;
+ *bufptr++ = attr->values[i].resolution.xres >> 24;
+ *bufptr++ = attr->values[i].resolution.xres >> 16;
+ *bufptr++ = attr->values[i].resolution.xres >> 8;
+ *bufptr++ = attr->values[i].resolution.xres;
+ *bufptr++ = attr->values[i].resolution.yres >> 24;
+ *bufptr++ = attr->values[i].resolution.yres >> 16;
+ *bufptr++ = attr->values[i].resolution.yres >> 8;
+ *bufptr++ = attr->values[i].resolution.yres;
+ *bufptr++ = attr->values[i].resolution.units;
+ }
+ break;
+
+ case IPP_TAG_RANGE :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if ((sizeof(buffer) - (bufptr - buffer)) < 13)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ *bufptr++ = 0;
+ *bufptr++ = 8;
+ *bufptr++ = attr->values[i].range.lower >> 24;
+ *bufptr++ = attr->values[i].range.lower >> 16;
+ *bufptr++ = attr->values[i].range.lower >> 8;
+ *bufptr++ = attr->values[i].range.lower;
+ *bufptr++ = attr->values[i].range.upper >> 24;
+ *bufptr++ = attr->values[i].range.upper >> 16;
+ *bufptr++ = attr->values[i].range.upper >> 8;
+ *bufptr++ = attr->values[i].range.upper;
+ }
+ break;
+
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = strlen(attr->values[i].string.charset) +
+ strlen(attr->values[i].string.text) +
+ 4;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ /* Length of entire value */
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Length of charset */
+ n = strlen(attr->values[i].string.charset);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Charset */
+ memcpy(bufptr, attr->values[i].string.charset, n);
+ bufptr += n;
+
+ /* Length of text */
+ n = strlen(attr->values[i].string.text);
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Text */
+ memcpy(bufptr, attr->values[i].string.text, n);
+ bufptr += n;
+ }
+ break;
+
+ default :
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ {
+ /*
+ * Arrays and sets are done by sending additional
+ * values with a zero-length name...
+ */
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < 3)
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ippWrite: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ *bufptr++ = attr->value_tag;
+ *bufptr++ = 0;
+ *bufptr++ = 0;
+ }
+
+ n = attr->values[i].unknown.length;
+
+ if (n > sizeof(buffer))
+ return (IPP_ERROR);
+
+ if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
+ {
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ return (IPP_ERROR);
+ }
+
+ bufptr = buffer;
+ }
+
+ /* Length of unknown value */
+ *bufptr++ = n >> 8;
+ *bufptr++ = n;
+
+ /* Value */
+ if (n > 0)
+ {
+ memcpy(bufptr, attr->values[i].unknown.data, n);
+ bufptr += n;
+ }
+ }
+ break;
+ }
+
+ /*
+ * Write the data out...
+ */
+
+ if (write(fd, (char *)buffer, bufptr - buffer) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ DEBUG_printf(("ipp_write_file: wrote %d bytes\n", bufptr - buffer));
+ }
+
+ if (ipp->current == NULL)
+ {
+ /*
+ * Done with all of the attributes; add the end-of-attributes tag...
+ */
+
+ buffer[0] = IPP_TAG_END;
+ if (write(fd, (char *)buffer, 1) < 0)
+ {
+ DEBUG_puts("ipp_write_file: Could not write IPP end-tag...");
+ close(fd);
+ return (IPP_ERROR);
+ }
+
+ ipp->state = IPP_DATA;
+ }
+ break;
+
+ case IPP_DATA :
+ break;
+ }
+
+ /*
+ * Close the file and return...
+ */
+
+ close(fd);
+
+ return (ipp->state);
+}
+
+
/*
* 'set_time()' - Set one of the "time-at-xyz" attributes...
*/
@@ -2049,5 +2990,5 @@ start_process(const char *command, /* I - Full path to command */
/*
- * End of "$Id: job.c,v 1.124.2.2 2001/05/13 18:38:36 mike Exp $".
+ * End of "$Id: job.c,v 1.124.2.3 2001/12/26 16:52:54 mike Exp $".
*/
diff --git a/scheduler/listen.c b/scheduler/listen.c
index a0c2549079..3b565bf35b 100644
--- a/scheduler/listen.c
+++ b/scheduler/listen.c
@@ -1,5 +1,5 @@
/*
- * "$Id: listen.c,v 1.9.2.1 2001/04/02 19:51:50 mike Exp $"
+ * "$Id: listen.c,v 1.9.2.2 2001/12/26 16:52:54 mike Exp $"
*
* Server listening routines for the Common UNIX Printing System (CUPS)
* scheduler.
@@ -107,7 +107,7 @@ StartListening(void)
memset(&ServerAddr, 0, sizeof(ServerAddr));
- if ((host = gethostbyname(ServerName)) != NULL)
+ if ((host = httpGetHostByName(ServerName)) != NULL)
{
/*
* Found the server's address!
@@ -216,5 +216,5 @@ StopListening(void)
/*
- * End of "$Id: listen.c,v 1.9.2.1 2001/04/02 19:51:50 mike Exp $".
+ * End of "$Id: listen.c,v 1.9.2.2 2001/12/26 16:52:54 mike Exp $".
*/
diff --git a/scheduler/log.c b/scheduler/log.c
index 5a92b0ccfb..7ea92f3b03 100644
--- a/scheduler/log.c
+++ b/scheduler/log.c
@@ -1,5 +1,5 @@
/*
- * "$Id: log.c,v 1.19 2001/02/21 20:16:47 mike Exp $"
+ * "$Id: log.c,v 1.19.2.1 2001/12/26 16:52:54 mike Exp $"
*
* Log file routines for the Common UNIX Printing System (CUPS).
*
@@ -86,7 +86,7 @@ GetDateTime(time_t t) /* I - Time value */
* log files. If you want GMT, set the TZ environment variable accordingly
* before starting the scheduler.
*
- * (*BSD stores the timezone offset in the tm structure)
+ * (*BSD and Darwin store the timezone offset in the tm structure)
*/
date = localtime(&t);
@@ -94,11 +94,11 @@ GetDateTime(time_t t) /* I - Time value */
snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
date->tm_hour, date->tm_min, date->tm_sec,
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#ifdef HAVE_TM_GMTOFF
-date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
#else
-timezone / 3600, (timezone / 60) % 60);
-#endif /* __*BSD__ */
+#endif /* HAVE_TM_GMTOFF */
return (s);
}
@@ -436,5 +436,5 @@ check_log_file(FILE **log, /* IO - Log file */
/*
- * End of "$Id: log.c,v 1.19 2001/02/21 20:16:47 mike Exp $".
+ * End of "$Id: log.c,v 1.19.2.1 2001/12/26 16:52:54 mike Exp $".
*/
diff --git a/scheduler/main.c b/scheduler/main.c
index 494a4b7805..e143e3eef5 100644
--- a/scheduler/main.c
+++ b/scheduler/main.c
@@ -1,5 +1,5 @@
/*
- * "$Id: main.c,v 1.57.2.1 2001/05/13 18:38:37 mike Exp $"
+ * "$Id: main.c,v 1.57.2.2 2001/12/26 16:52:55 mike Exp $"
*
* Scheduler main loop for the Common UNIX Printing System (CUPS).
*
@@ -446,7 +446,12 @@ main(int argc, /* I - Number of command-line arguments */
if (Browsing)
{
if (FD_ISSET(BrowseSocket, &input))
- UpdateBrowseList();
+ UpdateCUPSBrowse();
+
+#ifdef HAVE_LIBSLP
+ if ((BrowseProtocols & BROWSE_SLP) && BrowseSLPRefresh <= time(NULL))
+ UpdateSLPBrowse();
+#endif /* HAVE_LIBSLP */
SendBrowseList();
}
@@ -740,5 +745,5 @@ usage(void)
/*
- * End of "$Id: main.c,v 1.57.2.1 2001/05/13 18:38:37 mike Exp $".
+ * End of "$Id: main.c,v 1.57.2.2 2001/12/26 16:52:55 mike Exp $".
*/
diff --git a/scheduler/ppds.c b/scheduler/ppds.c
index 578d5b6102..d17d6ff554 100644
--- a/scheduler/ppds.c
+++ b/scheduler/ppds.c
@@ -1,5 +1,5 @@
/*
- * "$Id: ppds.c,v 1.14.2.1 2001/05/13 18:38:38 mike Exp $"
+ * "$Id: ppds.c,v 1.14.2.2 2001/12/26 16:52:55 mike Exp $"
*
* PPD scanning routines for the Common UNIX Printing System (CUPS).
*
@@ -168,10 +168,26 @@ LoadPPDs(const char *d) /* I - Directory to scan... */
PPDs = ippNew();
+ /*
+ * First the raw driver...
+ */
+
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "ppd-name", NULL, "raw");
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "ppd-make", NULL, "Raw");
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "ppd-make-and-model", NULL, "Raw Queue");
+ ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
+ "ppd-natural-language", NULL, "en");
+
+ /*
+ * Then the PPD files...
+ */
+
for (i = num_ppds, ppd = ppds; i > 0; i --, ppd ++)
{
- if (i)
- ippAddSeparator(PPDs);
+ ippAddSeparator(PPDs);
ippAddString(PPDs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"ppd-name", NULL, ppd->ppd_name);
@@ -399,11 +415,8 @@ static void
load_ppds(const char *d, /* I - Actual directory */
const char *p) /* I - Virtual path in name */
{
-#ifdef HAVE_LIBZ
- gzFile fp; /* Pointer to file */
-#else
- FILE *fp; /* Pointer to file */
-#endif /* HAVE_LIBZ */
+ int i; /* Looping var */
+ buf_t fp; /* Pointer to file */
DIR *dir; /* Directory pointer */
DIRENT *dent; /* Directory entry */
struct stat fileinfo; /* File information */
@@ -411,10 +424,37 @@ load_ppds(const char *d, /* I - Actual directory */
line[1024], /* Line from backend */
*ptr, /* Pointer into name */
name[128], /* Name of PPD file */
- language[64], /* Device class */
- manufacturer[1024], /* Manufacturer */
- make_model[256]; /* Make and model */
- ppd_info_t *ppd; /* New PPD file */
+ language[64], /* PPD language version */
+ country[64], /* Country code */
+ manufacturer[256], /* Manufacturer */
+ make_model[256], /* Make and Model */
+ model_name[256], /* ModelName */
+ nick_name[256]; /* NickName */
+ ppd_info_t *ppd, /* New PPD file */
+ key; /* Search key */
+ int new_ppd; /* Is this a new PPD? */
+ struct /* LanguageVersion translation table */
+ {
+ const char *version, /* LanguageVersion string */
+ *language; /* Language code */
+ } languages[] =
+ {
+ { "chinese", "cn" },
+ { "english", "en" },
+ { "french", "fr" },
+ { "german", "de" },
+ { "danish", "da" },
+ { "finnish", "fi" },
+ { "italian", "it" },
+ { "dutch", "du" },
+ { "japanese", "jp" },
+ { "norwegian", "no" },
+ { "polish", "pl" },
+ { "portugese", "pt" },
+ { "russian", "ru" },
+ { "swedish", "sv" },
+ { "turkish", "tr" }
+ };
if ((dir = opendir(d)) == NULL)
@@ -568,8 +608,9 @@ load_ppds(const char *d, /* I - Actual directory */
*ptr = '\0';
else if (strncasecmp(manufacturer, "agfa", 4) == 0)
strcpy(manufacturer, "AGFA");
- else if (strncasecmp(manufacturer, "herk", 4) == 0)
- strcpy(manufacturer, "Linotype");
+ else if (strncasecmp(manufacturer, "herk", 4) == 0 ||
+ strncasecmp(manufacturer, "linotype", 8) == 0)
+ strcpy(manufacturer, "LHAG");
else
strcpy(manufacturer, "Other");
@@ -595,24 +636,57 @@ load_ppds(const char *d, /* I - Actual directory */
else if (strcasecmp(manufacturer, "designjet") == 0)
strcpy(manufacturer, "HP");
}
+ else if (strncasecmp(manufacturer, "LHAG", 4) == 0 ||
+ strncasecmp(manufacturer, "linotype", 8) == 0)
+ strcpy(manufacturer, "LHAG");
/*
* Fix the language as needed...
*/
- if (strcasecmp(language, "german") == 0)
- strcpy(language, "de");
- else if (strcasecmp(language, "spanish") == 0)
- strcpy(language, "es");
- else if (strlen(language) > 2)
+ if ((ptr = strchr(language, '-')) != NULL)
+ *ptr++ = '\0';
+ else if ((ptr = strchr(language, '_')) != NULL)
+ *ptr++ = '\0';
+
+ if (ptr)
+ {
+ /*
+ * Setup the country suffix...
+ */
+
+ country[0] = '_';
+ strcpy(country + 1, ptr);
+ }
+ else
+ {
+ /*
+ * No country suffix...
+ */
+
+ country[0] = '\0';
+ }
+
+ for (i = 0; i < (int)(sizeof(languages) / sizeof(languages[0])); i ++)
+ if (strcasecmp(languages[i].version, language) == 0)
+ break;
+
+ if (i < (int)(sizeof(languages) / sizeof(languages[0])))
+ {
+ /*
+ * Found a known language...
+ */
+
+ snprintf(language, sizeof(language), "%s%s", languages[i].language,
+ country);
+ }
+ else
{
/*
- * en, fr, it, etc.
+ * Unknown language; use "xx"...
*/
- language[0] = tolower(language[0]);
- language[1] = tolower(language[1]);
- language[2] = '\0';
+ strcpy(language, "xx");
}
/*
@@ -661,5 +735,5 @@ load_ppds(const char *d, /* I - Actual directory */
/*
- * End of "$Id: ppds.c,v 1.14.2.1 2001/05/13 18:38:38 mike Exp $".
+ * End of "$Id: ppds.c,v 1.14.2.2 2001/12/26 16:52:55 mike Exp $".
*/
diff --git a/scheduler/printers.c b/scheduler/printers.c
index f2b34a6cff..05e0b2ff17 100644
--- a/scheduler/printers.c
+++ b/scheduler/printers.c
@@ -1,5 +1,5 @@
/*
- * "$Id: printers.c,v 1.93.2.3 2001/05/13 18:38:38 mike Exp $"
+ * "$Id: printers.c,v 1.93.2.4 2001/12/26 16:52:55 mike Exp $"
*
* Printer routines for the Common UNIX Printing System (CUPS).
*
@@ -500,12 +500,12 @@ LoadAllPrinters(void)
continue;
/*
- * Strip trailing newline, if any...
+ * Strip trailing whitespace, if any...
*/
len = strlen(line);
- if (line[len - 1] == '\n')
+ while (len > 0 && isspace(line[len - 1]))
{
len --;
line[len] = '\0';
@@ -754,10 +754,13 @@ SaveAllPrinters(void)
if (printer->info[0])
fprintf(fp, "Info %s\n", printer->info);
- if (printer->more_info[0])
+
+ if (printer->location[0])
fprintf(fp, "Location %s\n", printer->location);
+
if (printer->device_uri[0])
fprintf(fp, "DeviceURI %s\n", printer->device_uri);
+
if (printer->state == IPP_PRINTER_STOPPED)
{
fputs("State Stopped\n", fp);
@@ -765,19 +768,18 @@ SaveAllPrinters(void)
}
else
fputs("State Idle\n", fp);
+
if (printer->accepting)
fputs("Accepting Yes\n", fp);
else
fputs("Accepting No\n", fp);
+
fprintf(fp, "JobSheets %s %s\n", printer->job_sheets[0],
printer->job_sheets[1]);
- if (printer->quota_period)
- {
- fprintf(fp, "QuotaPeriod %d\n", printer->quota_period);
- fprintf(fp, "PageLimit %d\n", printer->page_limit);
- fprintf(fp, "KLimit %d\n", printer->k_limit);
- }
+ fprintf(fp, "QuotaPeriod %d\n", printer->quota_period);
+ fprintf(fp, "PageLimit %d\n", printer->page_limit);
+ fprintf(fp, "KLimit %d\n", printer->k_limit);
for (i = 0; i < printer->num_users; i ++)
fprintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow",
@@ -807,8 +809,8 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
char filename[1024]; /* Name of PPD file */
int num_media; /* Number of media options */
location_t *auth; /* Pointer to authentication element */
- int auth_len; /* Length of class or printer resource */
const char *auth_supported; /* Authentication supported */
+ cups_ptype_t printer_type; /* Printer type data */
ppd_file_t *ppd; /* PPD file data */
ppd_option_t *input_slot, /* InputSlot options */
*media_type, /* MediaType options */
@@ -926,15 +928,9 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
if (!(p->type & CUPS_PRINTER_REMOTE))
{
if (p->type & CUPS_PRINTER_CLASS)
- {
- auth_len = 8;
snprintf(resource, sizeof(resource), "/classes/%s", p->name);
- }
else
- {
- auth_len = 9;
snprintf(resource, sizeof(resource), "/printers/%s", p->name);
- }
for (i = NumLocations, auth = Locations; i > 0; i --, auth ++)
if (strcmp(auth->location, resource) == 0)
@@ -987,7 +983,7 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
NULL, p->info);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
- NULL, p->more_info);
+ NULL, p->uri);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"pdl-override-supported", NULL, "not-attempted");
ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
@@ -1013,8 +1009,9 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
"generated-natural-language-supported", NULL, DefaultLanguage);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
"document-format-default", NULL, "application/octet-stream");
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
- "document-format-supported", NULL, "application/octet-stream");
+ ippAddStrings(p->attrs, IPP_TAG_PRINTER,
+ (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY),
+ "document-format-supported", NumMimeTypes, NULL, MimeTypes);
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"compression-supported", NULL, "none");
ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
@@ -1059,9 +1056,9 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
* Setup the job-sheets-supported and job-sheets-default attributes...
*/
- if (Classification[0])
- attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
- "job-sheets-supported", 2, NULL, NULL);
+ if (Classification[0] && !ClassifyOverride)
+ attr = ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-supported", NULL, Classification);
else
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"job-sheets-supported", NumBanners + 1, NULL, NULL);
@@ -1070,7 +1067,7 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
LogMessage(L_EMERG, "SetPrinterAttrs: Unable to allocate memory for "
"job-sheets-supported attribute: %s!",
strerror(errno));
- else
+ else if (!Classification[0] || ClassifyOverride)
{
attr->values[0].string.text = strdup("none");
@@ -1083,16 +1080,21 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
}
}
- attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
- "job-sheets-default", 2, NULL, NULL);
-
- if (attr != NULL)
+ if (!(p->type & CUPS_PRINTER_REMOTE))
{
- attr->values[0].string.text = strdup(p->job_sheets[0]);
- attr->values[1].string.text = strdup(p->job_sheets[1]);
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-default", 2, NULL, NULL);
+
+ if (attr != NULL)
+ {
+ attr->values[0].string.text = strdup(p->job_sheets[0]);
+ attr->values[1].string.text = strdup(p->job_sheets[1]);
+ }
}
}
+ printer_type = p->type;
+
if (p->type & CUPS_PRINTER_REMOTE)
{
/*
@@ -1216,7 +1218,12 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, ppd->nickname);
- strncpy(p->make_model, ppd->nickname, sizeof(p->make_model) - 1);
+ if (ppd->nickname)
+ strncpy(p->make_model, ppd->nickname, sizeof(p->make_model) - 1);
+ else if (ppd->modelname)
+ strncpy(p->make_model, ppd->modelname, sizeof(p->make_model) - 1);
+ else
+ strcpy(p->make_model, "Bad PPD File");
/*
* Add media options from the PPD file...
@@ -1337,6 +1344,8 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
AddPrinterFilter(p, "application/vnd.cups-postscript 0 -");
ppdClose(ppd);
+
+ printer_type = p->type;
}
else if (access(filename, 0) == 0)
{
@@ -1365,6 +1374,38 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
ServerRoot, p->name);
AddPrinterFilter(p, filename);
}
+ else if (strncmp(p->device_uri, "ipp://", 6) == 0 &&
+ (strstr(p->device_uri, "/printers/") != NULL ||
+ strstr(p->device_uri, "/classes/") != NULL))
+ {
+ /*
+ * Tell the client this is really a hard-wired remote printer.
+ */
+
+ printer_type |= CUPS_PRINTER_REMOTE;
+
+ /*
+ * Reset the printer-uri-supported attribute to point at the
+ * remote printer...
+ */
+
+ attr = ippFindAttribute(p->attrs, "printer-uri-supported", IPP_TAG_URI);
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(p->device_uri);
+
+ /*
+ * Then set the make-and-model accordingly...
+ */
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-make-and-model", NULL, "Remote Printer");
+
+ /*
+ * Print all files directly...
+ */
+
+ AddPrinterFilter(p, "*/* 0 -");
+ }
else
{
/*
@@ -1390,7 +1431,8 @@ SetPrinterAttrs(printer_t *p) /* I - Printer to setup */
* Add the CUPS-specific printer-type attribute...
*/
- ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", p->type);
+ ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type",
+ printer_type);
DEBUG_printf(("SetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
p->type));
@@ -1793,5 +1835,5 @@ write_printcap(void)
/*
- * End of "$Id: printers.c,v 1.93.2.3 2001/05/13 18:38:38 mike Exp $".
+ * End of "$Id: printers.c,v 1.93.2.4 2001/12/26 16:52:55 mike Exp $".
*/
diff --git a/scheduler/printers.h b/scheduler/printers.h
index fb0f550779..5f2329a023 100644
--- a/scheduler/printers.h
+++ b/scheduler/printers.h
@@ -1,5 +1,5 @@
/*
- * "$Id: printers.h,v 1.22 2001/01/22 15:04:01 mike Exp $"
+ * "$Id: printers.h,v 1.22.2.1 2001/12/26 16:52:55 mike Exp $"
*
* Printer definitions for the Common UNIX Printing System (CUPS) scheduler.
*
@@ -47,8 +47,7 @@ typedef struct printer_str
name[IPP_MAX_NAME], /* Printer name */
location[IPP_MAX_NAME], /* Location code */
make_model[IPP_MAX_NAME],/* Make and model */
- info[IPP_MAX_NAME], /* Description */
- more_info[HTTP_MAX_URI];/* URL for site-specific info */
+ info[IPP_MAX_NAME]; /* Description */
int accepting; /* Accepting jobs? */
ipp_pstate_t state; /* Printer state */
char state_message[1024]; /* Printer state message */
@@ -114,5 +113,5 @@ extern const char *ValidateDest(const char *hostname,
/*
- * End of "$Id: printers.h,v 1.22 2001/01/22 15:04:01 mike Exp $".
+ * End of "$Id: printers.h,v 1.22.2.1 2001/12/26 16:52:55 mike Exp $".
*/
diff --git a/scheduler/quotas.c b/scheduler/quotas.c
index f569bbd557..339a75c9f6 100644
--- a/scheduler/quotas.c
+++ b/scheduler/quotas.c
@@ -1,5 +1,5 @@
/*
- * "$Id: quotas.c,v 1.4 2001/01/22 15:04:01 mike Exp $"
+ * "$Id: quotas.c,v 1.4.2.1 2001/12/26 16:52:55 mike Exp $"
*
* Quota routines for the Common UNIX Printing System (CUPS).
*
@@ -182,7 +182,7 @@ UpdateQuota(printer_t *p, /* I - Printer */
next = job->next;
if (strcasecmp(job->dest, p->name) != 0 ||
- strcmp(job->username, q->username) != 0)
+ strcasecmp(job->username, q->username) != 0)
continue;
if ((attr = ippFindAttribute(job->attrs, "time-at-completion",
@@ -227,10 +227,10 @@ static int /* O - Result of comparison */
compare(const quota_t *q1, /* I - First quota record */
const quota_t *q2) /* I - Second quota record */
{
- return (strcmp(q1->username, q2->username));
+ return (strcasecmp(q1->username, q2->username));
}
/*
- * End of "$Id: quotas.c,v 1.4 2001/01/22 15:04:01 mike Exp $".
+ * End of "$Id: quotas.c,v 1.4.2.1 2001/12/26 16:52:55 mike Exp $".
*/
diff --git a/scheduler/type.c b/scheduler/type.c
index fcb444d23f..c44f7c1c74 100644
--- a/scheduler/type.c
+++ b/scheduler/type.c
@@ -1,5 +1,5 @@
/*
- * "$Id: type.c,v 1.11 2001/02/07 19:41:38 mike Exp $"
+ * "$Id: type.c,v 1.11.2.1 2001/12/26 16:52:55 mike Exp $"
*
* MIME typing routines for the Common UNIX Printing System (CUPS).
*
@@ -902,7 +902,7 @@ checkrules(const char *filename, /* I - Filename */
break;
case MIME_MAGIC_LOCALE :
- result = (strcmp(rules->value.localev, setlocale(LC_ALL, NULL)) == 0);
+ result = (strcmp(rules->value.localev, setlocale(LC_MESSAGES, NULL)) == 0);
break;
case MIME_MAGIC_CONTAINS :
@@ -1086,5 +1086,5 @@ patmatch(const char *s, /* I - String to match against */
/*
- * End of "$Id: type.c,v 1.11 2001/02/07 19:41:38 mike Exp $".
+ * End of "$Id: type.c,v 1.11.2.1 2001/12/26 16:52:55 mike Exp $".
*/
diff --git a/systemv/Makefile b/systemv/Makefile
index 270277692b..7d9b1a5e70 100644
--- a/systemv/Makefile
+++ b/systemv/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.23 2001/01/22 15:04:02 mike Exp $"
+# "$Id: Makefile,v 1.23.2.1 2001/12/26 16:52:56 mike Exp $"
#
# System V commands makefile for the Common UNIX Printing System (CUPS).
#
@@ -24,10 +24,10 @@
include ../Makedefs
-TARGETS = accept cancel lp lpadmin lpinfo lpmove lpoptions lppasswd \
- lpstat
-OBJS = accept.o cancel.o lp.o lpadmin.o lpinfo.o lpmove.o \
- lpoptions.o lppasswd.o lpstat.o
+TARGETS = accept cancel cupsaddsmb lp lpadmin lpinfo lpmove \
+ lpoptions lppasswd lpstat
+OBJS = accept.o cancel.o cupsaddsmb.o lp.o lpadmin.o \
+ lpinfo.o lpmove.o lpoptions.o lppasswd.o lpstat.o
#
@@ -49,30 +49,24 @@ clean:
# Install all targets...
#
-install: $(INSTALL_SYSV)
- -$(MKDIR) $(BINDIR)
- $(CHMOD) ugo+rx $(BINDIR)
- $(INSTALL_BIN) accept lpadmin lpinfo lpmove $(SBINDIR)
- $(INSTALL_BIN) cancel lp lpoptions lppasswd lpstat $(BINDIR)
- $(CHMOD) u+s $(BINDIR)/lppasswd
+install:
+ $(INSTALL_DIR) $(BINDIR)
+ $(INSTALL_BIN) accept $(SBINDIR)
$(RM) $(SBINDIR)/reject
$(LN) accept $(SBINDIR)/reject
+ $(INSTALL_BIN) cupsaddsmb $(SBINDIR)
+ $(INSTALL_BIN) lpadmin $(SBINDIR)
+ $(INSTALL_BIN) lpinfo $(SBINDIR)
+ $(INSTALL_BIN) lpmove $(SBINDIR)
+ $(INSTALL_BIN) cancel $(BINDIR)
$(RM) $(BINDIR)/disable
$(LN) ../sbin/accept $(BINDIR)/disable
$(RM) $(BINDIR)/enable
$(LN) ../sbin/accept $(BINDIR)/enable
-
-install-sysv:
- -$(MKDIR) $(LIBDIR)
- $(CHMOD) ugo+rx $(LIBDIR)
- $(RM) $(LIBDIR)/lpadmin
- $(LN) ../sbin/lpadmin $(LIBDIR)
- $(RM) $(LIBDIR)/lpmove
- $(LN) ../sbin/lpmove $(LIBDIR)
- $(RM) $(LIBDIR)/accept
- $(LN) ../sbin/accept $(LIBDIR)
- $(RM) $(LIBDIR)/reject
- $(LN) ../sbin/accept $(LIBDIR)/reject
+ $(INSTALL_BIN) lp $(BINDIR)
+ $(INSTALL_BIN) lpoptions $(BINDIR)
+ $(INSTALL_BIN) lpstat $(BINDIR)
+ $(INSTALL_BIN) -m 4755 -o $(CUPS_USER) -g $(CUPS_GROUP) lppasswd $(BINDIR)
#
@@ -82,6 +76,10 @@ install-sysv:
accept: accept.o ../cups/$(LIBCUPS)
echo Linking $@...
$(CC) $(LDFLAGS) -o accept accept.o $(LIBS)
+ $(RM) reject enable disable
+ $(LN) accept reject
+ $(LN) accept enable
+ $(LN) accept disable
accept.o: ../cups/cups.h
@@ -97,6 +95,17 @@ cancel: cancel.o ../cups/$(LIBCUPS)
cancel.o: ../cups/cups.h
+#
+# cupsaddsmb
+#
+
+cupsaddsmb: cupsaddsmb.o ../cups/$(LIBCUPS)
+ echo Linking $@...
+ $(CC) $(LDFLAGS) -o cupsaddsmb cupsaddsmb.o $(LIBS)
+
+cupsaddsmb.o: ../cups/cups.h ../cups/string.h
+
+
#
# lp
#
@@ -177,5 +186,5 @@ lpstat.o: ../cups/cups.h
$(OBJS): ../Makedefs
#
-# End of "$Id: Makefile,v 1.23 2001/01/22 15:04:02 mike Exp $".
+# End of "$Id: Makefile,v 1.23.2.1 2001/12/26 16:52:56 mike Exp $".
#
diff --git a/systemv/accept.c b/systemv/accept.c
index 272098c15c..e8726d0643 100644
--- a/systemv/accept.c
+++ b/systemv/accept.c
@@ -1,5 +1,5 @@
/*
- * "$Id: accept.c,v 1.11.2.1 2001/05/13 18:38:40 mike Exp $"
+ * "$Id: accept.c,v 1.11.2.2 2001/12/26 16:52:56 mike Exp $"
*
* "accept", "disable", "enable", and "reject" commands for the Common
* UNIX Printing System (CUPS).
@@ -57,6 +57,7 @@ main(int argc, /* I - Number of command-line arguments */
/* Name of printer or class */
uri[1024], /* Printer URI */
*reason; /* Reason for reject/disable */
+ const char *server; /* Server name */
ipp_t *request; /* IPP request */
ipp_t *response; /* IPP response */
ipp_op_t op; /* Operation */
@@ -90,6 +91,7 @@ main(int argc, /* I - Number of command-line arguments */
return (1);
}
+ server = cupsServer();
http = NULL;
reason = NULL;
encryption = cupsEncryption();
@@ -123,7 +125,7 @@ main(int argc, /* I - Number of command-line arguments */
httpClose(http);
if (argv[i][2] != '\0')
- http = httpConnectEncrypt(argv[i] + 2, ippPort(), encryption);
+ server = argv[i] + 2;
else
{
i ++;
@@ -134,9 +136,11 @@ main(int argc, /* I - Number of command-line arguments */
return (1);
}
- http = httpConnectEncrypt(argv[i], ippPort(), encryption);
+ server = argv[i];
}
+ http = httpConnectEncrypt(server, ippPort(), encryption);
+
if (http == NULL)
{
fputs(argv[0], stderr);
@@ -173,7 +177,10 @@ main(int argc, /* I - Number of command-line arguments */
*/
if (sscanf(argv[i], "%1023[^@]@%1023s", printer, hostname) == 1)
- strcpy(hostname, "localhost");
+ {
+ strncpy(hostname, server, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = '\0';
+ }
if (http != NULL && strcasecmp(http->hostname, hostname) != 0)
{
@@ -304,5 +311,5 @@ main(int argc, /* I - Number of command-line arguments */
/*
- * End of "$Id: accept.c,v 1.11.2.1 2001/05/13 18:38:40 mike Exp $".
+ * End of "$Id: accept.c,v 1.11.2.2 2001/12/26 16:52:56 mike Exp $".
*/
diff --git a/systemv/cupsaddsmb.c b/systemv/cupsaddsmb.c
index d4876a0891..3fffa42707 100644
--- a/systemv/cupsaddsmb.c
+++ b/systemv/cupsaddsmb.c
@@ -1,5 +1,5 @@
/*
- * "$Id: cupsaddsmb.c,v 1.3 2001/12/18 21:08:21 mike Exp $"
+ * "$Id: cupsaddsmb.c,v 1.3.2.1 2001/12/26 16:52:56 mike Exp $"
*
* "cupsaddsmb" command for the Common UNIX Printing System (CUPS).
*
@@ -282,5 +282,5 @@ export_dest(const char *dest) /* I - Destination to export */
/*
- * End of "$Id: cupsaddsmb.c,v 1.3 2001/12/18 21:08:21 mike Exp $".
+ * End of "$Id: cupsaddsmb.c,v 1.3.2.1 2001/12/26 16:52:56 mike Exp $".
*/
diff --git a/systemv/lp.c b/systemv/lp.c
index 902c0c1254..b1b7dedde4 100644
--- a/systemv/lp.c
+++ b/systemv/lp.c
@@ -1,5 +1,5 @@
/*
- * "$Id: lp.c,v 1.29.2.1 2001/05/13 18:38:40 mike Exp $"
+ * "$Id: lp.c,v 1.29.2.2 2001/12/26 16:52:56 mike Exp $"
*
* "lp" command for the Common UNIX Printing System (CUPS).
*
@@ -375,8 +375,9 @@ main(int argc, /* I - Number of command-line arguments */
if (strcmp(val, "hold") == 0)
num_options = cupsAddOption("job-hold-until", "indefinite",
num_options, &options);
- if (strcmp(val, "resume") == 0)
- num_options = cupsAddOption("job-hold-until", "none",
+ else if (strcmp(val, "resume") == 0 ||
+ strcmp(val, "release") == 0)
+ num_options = cupsAddOption("job-hold-until", "no-hold",
num_options, &options);
else if (strcmp(val, "immediate") == 0)
num_options = cupsAddOption("job-priority", "100",
@@ -529,7 +530,7 @@ main(int argc, /* I - Number of command-line arguments */
return (1);
}
- while ((i = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
+ while ((i = read(0, buffer, sizeof(buffer))) > 0)
write(temp, buffer, i);
i = lseek(temp, 0, SEEK_CUR);
@@ -556,8 +557,7 @@ main(int argc, /* I - Number of command-line arguments */
return (1);
}
else if (!silent)
- fprintf(stderr, "request id is %s-%d (%d file(s))\n", printer, job_id,
- num_files);
+ printf("request id is %s-%d (%d file(s))\n", printer, job_id, num_files);
return (0);
}
@@ -650,5 +650,5 @@ sighandler(int s) /* I - Signal number */
/*
- * End of "$Id: lp.c,v 1.29.2.1 2001/05/13 18:38:40 mike Exp $".
+ * End of "$Id: lp.c,v 1.29.2.2 2001/12/26 16:52:56 mike Exp $".
*/
diff --git a/systemv/lpadmin.c b/systemv/lpadmin.c
index 11ae41aed5..6432ce657d 100644
--- a/systemv/lpadmin.c
+++ b/systemv/lpadmin.c
@@ -1,5 +1,5 @@
/*
- * "$Id: lpadmin.c,v 1.22.2.1 2001/05/13 18:38:41 mike Exp $"
+ * "$Id: lpadmin.c,v 1.22.2.2 2001/12/26 16:52:57 mike Exp $"
*
* "lpadmin" command for the Common UNIX Printing System (CUPS).
*
@@ -33,6 +33,7 @@
* set_printer_file() - Set the interface script or PPD file.
* set_printer_info() - Set the printer description string.
* set_printer_location() - Set the printer location string.
+ * set_printer_model() - Set the driver model file.
* set_printer_options() - Set the printer options.
* validate_name() - Make sure the printer name only contains
* letters, numbers, and the underscore...
@@ -68,6 +69,7 @@ static void set_printer_device(http_t *, char *, char *);
static void set_printer_file(http_t *, char *, char *);
static void set_printer_info(http_t *, char *, char *);
static void set_printer_location(http_t *, char *, char *);
+static void set_printer_model(http_t *, char *, char *);
static void set_printer_options(http_t *, char *, int, cups_option_t *);
static int validate_name(const char *);
@@ -99,9 +101,6 @@ main(int argc, /* I - Number of command-line arguments */
options = NULL;
encryption = cupsEncryption();
- if ((datadir = getenv("CUPS_DATADIR")) == NULL)
- datadir = CUPS_DATADIR;
-
for (i = 1; i < argc; i ++)
if (argv[i][0] == '-')
switch (argv[i][1])
@@ -298,8 +297,7 @@ main(int argc, /* I - Number of command-line arguments */
}
if (argv[i][2])
- snprintf(filename, sizeof(filename), "%s/model/%s", datadir,
- argv[i] + 2);
+ set_printer_model(http, printer, argv[i] + 2);
else
{
i ++;
@@ -310,11 +308,8 @@ main(int argc, /* I - Number of command-line arguments */
return (1);
}
- snprintf(filename, sizeof(filename), "%s/model/%s", datadir,
- argv[i]);
+ set_printer_model(http, printer, argv[i]);
}
-
- set_printer_file(http, printer, filename);
break;
case 'o' : /* Set option */
@@ -1589,6 +1584,70 @@ set_printer_location(http_t *http, /* I - Server connection */
}
+/*
+ * 'set_printer_model()' - Set the driver model file.
+ */
+
+static void
+set_printer_model(http_t *http, /* I - Server connection */
+ char *printer, /* I - Printer */
+ char *model) /* I - Driver model file */
+{
+ ipp_t *request, /* IPP Request */
+ *response; /* IPP Response */
+ cups_lang_t *language; /* Default language */
+ char uri[HTTP_MAX_URI]; /* URI for printer/class */
+
+
+ /*
+ * Build a CUPS_ADD_PRINTER request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * ppd-name
+ */
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer);
+
+ request = ippNew();
+
+ request->request.op.operation_id = CUPS_ADD_PRINTER;
+ request->request.op.request_id = 1;
+
+ language = cupsLangDefault();
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+ "attributes-charset", NULL, cupsLangEncoding(language));
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+ "attributes-natural-language", NULL, language->language);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+ "printer-uri", NULL, uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "ppd-name", NULL, model);
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/admin/")) == NULL)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(cupsLastError()));
+ else
+ {
+ if (response->request.status.status_code > IPP_OK_CONFLICT)
+ fprintf(stderr, "lpadmin: add-printer failed: %s\n",
+ ippErrorString(response->request.status.status_code));
+
+ ippDelete(response);
+ }
+}
+
+
/*
* 'set_printer_options()' - Set the printer options.
*/
@@ -1770,5 +1829,5 @@ validate_name(const char *name) /* I - Name to check */
/*
- * End of "$Id: lpadmin.c,v 1.22.2.1 2001/05/13 18:38:41 mike Exp $".
+ * End of "$Id: lpadmin.c,v 1.22.2.2 2001/12/26 16:52:57 mike Exp $".
*/
diff --git a/templates/Makefile b/templates/Makefile
index 46ea7f6017..d439eda9ba 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -1,5 +1,5 @@
#
-# "$Id: Makefile,v 1.6 2001/01/22 15:04:03 mike Exp $"
+# "$Id: Makefile,v 1.6.2.1 2001/12/26 16:52:57 mike Exp $"
#
# Template makefile for the Common UNIX Printing System (CUPS).
#
@@ -51,6 +51,7 @@ FILES = add-class.tmpl \
job-cancel.tmpl \
job-hold.tmpl \
job-release.tmpl \
+ job-restart.tmpl \
modify-class.tmpl \
modify-printer.tmpl \
option-boolean.tmpl \
@@ -91,12 +92,12 @@ clean:
#
install:
- -$(MKDIR) $(DATADIR)/templates
- $(CHMOD) ugo+rx $(DATADIR)
- $(CHMOD) ugo+rx $(DATADIR)/templates
- $(INSTALL_DATA) $(FILES) $(DATADIR)/templates
+ $(INSTALL_DIR) $(DATADIR)/templates
+ for file in $(FILES); do \
+ $(INSTALL_DATA) $$file $(DATADIR)/templates; \
+ done
#
-# End of "$Id: Makefile,v 1.6 2001/01/22 15:04:03 mike Exp $".
+# End of "$Id: Makefile,v 1.6.2.1 2001/12/26 16:52:57 mike Exp $".
#
diff --git a/templates/choose-uri.tmpl b/templates/choose-uri.tmpl
index a432d99ca6..63bee8529b 100644
--- a/templates/choose-uri.tmpl
+++ b/templates/choose-uri.tmpl
@@ -22,14 +22,14 @@
Examples:
-
-
file:/path/to/filename.prn
- http://hostname:631/ipp/port1
- ipp://hostname/ipp/port1
- lpd://hostname/queue
- socket://hostname
- socket://hostname:9100
-
+
+ file:/path/to/filename.prn
+ http://hostname:631/ipp/port1
+ ipp://hostname/ipp/port1
+ lpd://hostname/queue
+ socket://hostname
+ socket://hostname:9100
+
diff --git a/templates/jobs.tmpl b/templates/jobs.tmpl
index a32677b882..d168cc1ae8 100644
--- a/templates/jobs.tmpl
+++ b/templates/jobs.tmpl
@@ -2,27 +2,27 @@

- ID
- Name
- User
- Size
- State
- Control
+ ID
+ Name
+ User
+ Size
+ State
+ Control

{[job_id]
-
+
- {job_id}
- {?job_name=?Unknown:{job_name}}
- {job_originating_user_name}
- {job_k_octets}k
- {job_state=3?pending:{job_state=4?held:
- {job_state=5?processing:{job_state=6?stopped:
- {job_state=7?cancelled:{job_state=8?aborted:completed}}}}}}
+ {job_printer_name}-{job_id}
+ {?job_name=?Unknown:{job_name}}
+ {job_originating_user_name}
+ {job_k_octets}k
+ {job_state=3?pending since
{time_at_creation}:{job_state=4?held since
{time_at_creation}:
+ {job_state=5?processing since
{time_at_processing}:{job_state=6?stopped at
{time_at_completed}:
+ {job_state=7?cancelled at
{time_at_completed}:{job_state=8?aborted:completed at
{time_at_completed}}}}}}}
{job_state>5?
{job_k_octets>0?
@@ -40,8 +40,7 @@
}
-
-
+
}
diff --git a/templates/option-header.tmpl b/templates/option-header.tmpl
index a23b1d2c1b..23a904178d 100644
--- a/templates/option-header.tmpl
+++ b/templates/option-header.tmpl
@@ -1,6 +1,6 @@

- {group}
+ {group}

diff --git a/templates/printer-accept.tmpl b/templates/printer-accept.tmpl
index 23d8c2f3cd..3a269eb0df 100644
--- a/templates/printer-accept.tmpl
+++ b/templates/printer-accept.tmpl
@@ -1 +1 @@
-Printer {printer_name} is now accepting jobs.
+
Printer {printer_name} is now accepting jobs.
diff --git a/templates/printer-reject.tmpl b/templates/printer-reject.tmpl
index 6cf330c4c5..e73d87380d 100644
--- a/templates/printer-reject.tmpl
+++ b/templates/printer-reject.tmpl
@@ -1 +1 @@
-
Printer {printer_name} is no longer accepting jobs.
+
Printer {printer_name} is no longer accepting jobs.
diff --git a/templates/trailer.tmpl b/templates/trailer.tmpl
index dc01c3771e..a584af7233 100644
--- a/templates/trailer.tmpl
+++ b/templates/trailer.tmpl
@@ -1,7 +1,7 @@
-The Common UNIX Printing System, CUPS, and the CUPS logo are the
-trademark property of Easy Software
-Products. CUPS is copyright 1997-2001 by Easy Software Products,
-All Rights Reserved.
+
Copyright 1993-2001 Easy Software Products, All Rights Reserved.
+The Common UNIX Printing System, CUPS, and the CUPS logo
+are the trademark property of Easy Software Products.
+All other trademarks are the property of their respective owners.