From: msweet Date: Fri, 10 May 2013 18:56:23 +0000 (+0000) Subject: Import cups.org releases X-Git-Tag: release-1.0b9^0 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8ed41c5f72bb28e3fd3f8243ec28138bc367da12;p=thirdparty%2Fcups.git Import cups.org releases git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/tags/release-1.0b9@4306 a1ca3aef-8c08-0410-bb20-df032aa958be --- 8ed41c5f72bb28e3fd3f8243ec28138bc367da12 diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 0000000000..7a25722a6e --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,386 @@ + + + Software License Agreement - Common UNIX Printing System + + + + +

Common UNIX Printing System License Agreement

+ +

Copyright 1997-1999 by Easy Software Products
+44141 AIRPORT VIEW DR STE 204
+HOLLYWOOD, MARYLAND 20636-3111 USA
+
+Voice: +1.301.373.9603
+Email: cups-info@cups.org
+WWW: http://www.cups.org + +

Introduction

+ +

The Common UNIX Printing SystemTM, or CUPSTM, +is provided under the GNU General Public License, Version 2. A copy of +this license follows this introduction. + +

For those not familiar with the GNU General Public License, the license +basically allows you to: + +

+ +

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 have to provide source for any new drivers, changes, or +additions to the software, and all code must be provided under the GPL. + +

Also, since we have trademarked the Common UNIX Printing System, CUPS, +and CUPS logo, you may not release a derivative product using those names +without permission from Easy Software Products. + +

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 or additions and modifications to +CUPS under the GPL. For pricing information please contact us at the +address shown above. + +

The Common UNIX Printing System utilizes GNU GhostScript 4.03 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 +
+ +

Support

+ +

Easy Software Products sells software support for distributors and +resellers of CUPS. Support for users of CUPS is available from Easy +Software Products through our ESP Print software. + +

Trademarks

+ +

The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software Products. Any derivative of this +software may not use any of these trademarks without the expressed +written consent of Easy Software Products. + +

GNU General Public License

+ +

Version 2, June 1991
+
+Copyright 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +

Everyone is permitted to copy and distribute verbatim +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. + +

GNU GENERAL PUBLIC LICENSE
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

+ +
    + +
  1. 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. + +

  2. 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. + +

  3. 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: + +
      + +
    1. You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +
    2. 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. + +
    3. 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. + +

  4. 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: + +
      + +
    1. 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, + +
    2. 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, + +
    3. 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. + +

  5. 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. + +
  6. 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. + +
  7. 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. + +
  8. 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. + +

  9. 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. + +
  10. 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. + +

  11. 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

+ +
    + +
  1. 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. + +
  2. 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

+ + + diff --git a/Makedefs.in b/Makedefs.in new file mode 100644 index 0000000000..19b96ea12d --- /dev/null +++ b/Makedefs.in @@ -0,0 +1,138 @@ +# +# "$Id$" +# +# Common makefile definitions for the Common UNIX Printing System (CUPS). +# +# @configure_input@ +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +# +# Programs... +# + +AR = @AR@ +AWK = @AWK@ +CC = @CC@ +CHMOD = @CHMOD@ +CP = @CP@ +DSO = @DSO@ +HTMLDOC = @HTMLDOC@ +LN = /bin/ln -sf +MKDIR = @MKDIR@ -p +NROFF = @NROFF@ +PACK = @PACK@ +RANLIB = @RANLIB@ +RM = @RM@ -f +SED = @SED@ +SHELL = /bin/sh +SMBCLIENT = @SMBCLIENT@ + +# +# Libraries... +# + +LIBCUPS = @LIBCUPS@ +LIBCUPSIMAGE = @LIBCUPSIMAGE@ +LIBJPEG = @LIBJPEG@ +LIBPNG = @LIBPNG@ +LIBTIFF = @LIBTIFF@ +LIBZ = @LIBZ@ + +# +# Program options... +# +# OPTIM defines the common compiler optimization/debugging options. +# OPTIONS defines other compile-time options (currently only -dDEBUG for +# extra debug info) +# + +ARFLAGS = crvs +CFLAGS = @CFLAGS@ $(OPTIM) -I.. $(OPTIONS) +DSOLIBS = @DSOLIBS@ +IMGLIBS = @IMGLIBS@ -lm +LDFLAGS = @LDFLAGS@ $(OPTIM) +LIBS = -L../cups -lcups $(NETLIBS) @LIBS@ +NETLIBS = @NETLIBS@ +OPTIM = @OPTIM@ +OPTIONS = + +# +# Formatted man page extension... +# + +CAT = @CAT@ + +# +# Directories... +# +# The first section uses the GNU names (which are *extremely* +# difficult to find in a makefile because they are lowercase...) +# We have to define these first because autoconf uses ${prefix} +# and ${exec_prefix} for most of the other directories... +# +# This is immediately followed by definition in ALL CAPS for the +# needed directories... +# + +bindir = @bindir@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +includedir = @includedir@ +infodir = @infodir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +top_srcdir = @top_srcdir@ + +BINDIR = @bindir@ +DATADIR = @CUPS_DATADIR@ +INCLUDEDIR = $(includedir) +LIBDIR = $(libdir) +LOCALEDIR = @CUPS_LOCALEDIR@ +MANDIR = @mandir@ +SBINDIR = @sbindir@ +SERVERROOT = @CUPS_SERVERROOT@ + +# +# Rules... +# + +.SILENT: +.SUFFIXES: .a .c .gz .h .o .z .1 .5 .8 +.c.o: + echo Compiling $<... + $(CC) $(CFLAGS) -c $< +.1.z .5.z .8.z .1.gz .5.gz .8.gz: + echo Formatting $<... + $(NROFF) -man $< >t + $(PACK) t + -mv t.$(CAT) $@ + +# +# End of "$Id$" +# diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..934bf137c8 --- /dev/null +++ b/Makefile @@ -0,0 +1,76 @@ +# +# "$Id$" +# +# Top-level Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include Makedefs + +# +# Directories to make... +# + +DIRS = cups backend berkeley cgi-bin filter man pstoraster \ + scheduler systemv + +# +# Make all targets... +# + +all: + for dir in $(DIRS); do\ + echo Making all in $$dir... ;\ + (cd $$dir; make);\ + done + +# +# Remove object and target files... +# + +clean: + for dir in $(DIRS); do\ + echo Cleaning in $$dir... ;\ + (cd $$dir; make clean);\ + done + +# +# Install object and target files... +# + +install: + for dir in $(DIRS); do\ + echo Installing in $$dir... ;\ + (cd $$dir; make install);\ + done + echo Installing in conf... + (cd conf; make install) + echo Installing in data... + (cd data; make install) + echo Installing in doc... + (cd doc; make install) + echo Installing in fonts... + (cd fonts; make install) + echo Installing in ppd... + (cd ppd; make install) + +# +# End of "$Id$". +# diff --git a/README.txt b/README.txt new file mode 100644 index 0000000000..027f7c4e55 --- /dev/null +++ b/README.txt @@ -0,0 +1,195 @@ +README - CUPS v1.0b9 - 09/03/1999 +--------------------------------- + +BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE + + WARNING - This is a BETA release of CUPS, which means that it may + contain "bugs" that could prevent you from printing. If + you are concerned that this may cause you lost time or + money, please STOP and do not install this software! + +BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE + + +INTRODUCTION + +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +CUPS adds network printer browsing and PostScript Printer Description +("PPD")-based printing options to support real world applications under +UNIX. + +CUPS also includes a customized version of GNU GhostScript (currently +based off GNU GhostScript 4.03) and an image file RIP that can be used +to support non-PostScript printers. + +CUPS is Copyright 1993-1999 by Easy Software Products, All Rights +Reserved. CUPS is currently licensed under the terms of the GNU +General Public License. Please see the license file for details. + + +SYSTEM REQUIREMENTS + +Binary distributions require a minimum of 10MB of free disk space. We +do not recommend using CUPS on a workstation with less than 32MB of RAM +or a PC with less than 16MB of RAM. + +If you are installing from source you'll need an ANSI C compiler and +optionally one or more image file support libraries. Complete source +installation instructions can be found in the CUPS System +Administrator's Manual in the files "doc/sam.html" or "doc/sam.pdf". + + +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 + - HP-UX 10.20 or higher + - IRIX 5.3 or higher + - Linux 2.0 with glibc2 or higher (tested with RedHat 5.2) + - Solaris 2.5 or higher (SPARC or Intel) + + +INSTALLING CUPS + +We are currently distributing CUPS binary distributions in TAR format +with installation and removal scripts generated by our ESP Package +Manager (EPM) software, which is also included with the source +distribution. + +WARNING: Installing CUPS will overwrite your existing printing system. +Backup files are made by the installation script and restored by the +removal script, so if you experience problems you should be able to +remove the CUPS software to restore your previous configuration. +However, Easy Software Products makes no warranty for this and will not +be liable for any lost revenues, etc. + +To install the CUPS software you will need to be logged in as root +(doing an "su" is good enough). Once you are the root user, run the +installation script with: + + ./cups.install ENTER + +After asking you a few yes/no questions the CUPS software will be +installed and the scheduler will be started automatically. + + +SETTING UP PRINTER QUEUES + +CUPS works best with PPD (PostScript Printer Description) files. In a +pinch you can also use System V style printer interface scripts. + +Two sample PPD files are provided with this distribution that utilize +the PostScript and image file RIPs and the sample HP printer driver. +To add the sample DeskJet driver to the system for a printer connected +to the parallel port, use one of the following commands: + + Digital UNIX: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/lp0 -E + + HP-UX: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/c2t0d0_lp -E + + IRIX: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/plp -E + + Linux: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/par0 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/par1 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/par2 -E + + Solaris: + + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/bpp0 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/ecpp0 -E + +Similarly, for the sample LaserJet driver you can use "LaserJet" and +"laserjet.ppd". + +For other printers and interfaces see the CUPS System Administator's +Manual included with this software. + +If you're interested in a complete, commercial printing solution for +UNIX, check out our ESP Print Pro software at: + + http://www.easysw.com/printpro + + +PRINTING FILES + +CUPS provides both the System V "lp" and Berkeley "lpr" commands for +printing: + + lp filename + lpr filename + +Both the "lp" and "lpr" commands support printing options for the +driver: + + lp -omedia=A4 -oresolution=600dpi filename + lpr -omedia=A4 -oresolution=600dpi filename + +CUPS recognizes many types of images files as well as PostScript, HP-GL/2, +and text files, so you can print those files directly rather than through +an application. + +If you have an application that generates output specifically for your +printer then you need to use the "-oraw" or "-l" options: + + lp -oraw filename + lpr -l filename + +This will prevent the filters from misinterpreting your print file. + + +REPORTING PROBLEMS + +If you have problems, please send an email to cups-support@cups.org. +Include your operating system and version, compiler and version, and +any errors or problems you've run into. + + +OTHER RESOURCES + +See the CUPS web site at "http://www.cups.org" for other site links. + +You can subscribe to the CUPS mailing list by sending a message +containing "subscribe cups" to majordomo@cups.org. This list is +provided to discuss problems, questions, and improvements to the CUPS +software. New releases of CUPS are announced to this list as well. + + +LEGAL STUFF + +CUPS is Copyright 1993-1999 by Easy Software Products. CUPS, the CUPS +logo, and the Common UNIX Printing System are the trademark property of +Easy Software Products. + +CUPS is provided under the terms of the GNU General Public License +which is located in the files "LICENSE.html" and "LICENSE.txt" (or the +file "cups.license" for a binary distribution.) For commercial +licensing information, please contact: + + Attn: CUPS Licensing Information + Easy Software Products + 44141 Airport View Drive, Suite 204 + Hollywood, Maryland 20636-3111 USA + + Voice: +1.301.373.9603 + Email: cups-info@cups.org + WWW: http://www.cups.org diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 0000000000..b4915aa5c2 --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,119 @@ +# +# "$Id$" +# +# Backend makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +TARGETS = ipp lpd parallel serial smb socket +OBJS = ipp.o lpd.o parallel.o serial.o socket.o + +# +# Make all targets... +# + +all: $(TARGETS) + +# +# Clean all object files... +# + +clean: + rm -f $(OBJS) $(TARGETS) + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERROOT)/backend + $(CP) $(TARGETS) $(SERVERROOT)/backend + -$(LN) ipp $(SERVERROOT)/backend/http + $(CHMOD) u+s $(SERVERROOT)/backend/lpd + +# +# ipp +# + +ipp: ipp.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o ipp ipp.o $(LIBS) + -$(LN) ipp http + +ipp.o: ../cups/cups.h ../Makedefs + +# +# lpd +# + +lpd: lpd.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpd lpd.o $(LIBS) + +lpd.o: ../cups/cups.h ../Makedefs + +# +# parallel +# + +parallel: parallel.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o parallel parallel.o $(LIBS) + +parallel.o: ../cups/cups.h ../Makedefs + +# +# serial +# + +serial: serial.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o serial serial.o $(LIBS) + +serial.o: ../cups/cups.h ../Makedefs + +# +# smb +# +# Note: reading through these commands is a good way to get a headache... :) +# + +smb: smb.sh ../Makedefs + echo Generating $@... + $(RM) smb + sedcmd="1,\$$s/^SMBCLIENT=.\*/SMBCLIENT=`echo $(SMBCLIENT) | sed -e '1,$$s/\\//\\\\\\//g'`/" ;\ + $(SED) -e "$$sedcmd" smb + $(CHMOD) +x smb + +# +# socket +# + +socket: socket.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o socket socket.o $(LIBS) + +socket.o: ../cups/cups.h ../Makedefs + +# +# End of "$Id$". +# diff --git a/backend/ipp.c b/backend/ipp.c new file mode 100644 index 0000000000..e73135fa73 --- /dev/null +++ b/backend/ipp.c @@ -0,0 +1,407 @@ +/* + * "$Id$" + * + * IPP backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the printer or server. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + int n, n2; /* Attribute values */ + char *option, /* Name of option */ + *val, /* Pointer to option value */ + *s; /* Pointer into option value */ + int num_options; /* Number of printer options */ + cups_option_t *options; /* Printer options */ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info */ + resource[1024], /* Resource info (printer name) */ + filename[1024]; /* File to print */ + int port; /* Port number (not used) */ + char password[255], /* Password info */ + uri[HTTP_MAX_URI];/* Updated URI without user/pass */ + http_status_t status; /* Status of HTTP job */ + FILE *fp; /* File to print */ + http_t *http; /* HTTP connection */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *job_id; /* job-id attribute */ + cups_lang_t *language; /* Default language */ + struct stat fileinfo; /* File statistics */ + size_t nbytes, /* Number of bytes written */ + tbytes; /* Total bytes written */ + char buffer[8192]; /* Output buffer */ + + + if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, print stdin... + */ + + if (argc == 6) + fp = stdin; + else if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: Unable to open print file"); + return (1); + } + else + stat(argv[6], &fileinfo); + + /* + * Extract the hostname and printer name from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * Try connecting to the remote server... + */ + + fprintf(stderr, "INFO: Connecting to %s...\n", hostname); + + if ((http = httpConnect(hostname, port)) == NULL) + { + perror("ERROR: Unable to connect to IPP host"); + + if (fp != stdin) + fclose(fp); + return (1); + } + + /* + * Build a URI for the printer and fill the standard IPP attributes for + * an IPP_PRINT_FILE request. We can't use the URI in argv[0] because it + * might contain username:password information... + */ + + request = ippNew(); + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + + sprintf(uri, "%s://%s:%d%s", method, hostname, port, resource); + + 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 != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, argv[2]); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, argv[3]); + + /* + * Handle options on the command-line... + */ + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + if (cupsGetOption("raw", num_options, options)) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/vnd.cups-raw"); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/octet-stream"); + + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", atoi(argv[4])); + + for (i = 0; i < num_options; i ++) + { + /* + * Skip the "raw" option - handled above... + */ + + if (strcmp(options[i].name, "raw") == 0) + continue; + + /* + * See what the option value is; for compatibility with older interface + * scripts, we have to support single-argument options as well as + * option=value, option=low-high, and option=MxN. + */ + + option = options[i].name; + val = options[i].value; + + if (*val == '\0') + val = NULL; + + if (val != NULL) + { + if (strcasecmp(val, "true") == 0 || + strcasecmp(val, "on") == 0 || + strcasecmp(val, "yes") == 0) + { + /* + * Boolean value - true... + */ + + n = 1; + val = ""; + } + else if (strcasecmp(val, "false") == 0 || + strcasecmp(val, "off") == 0 || + strcasecmp(val, "no") == 0) + { + /* + * Boolean value - false... + */ + + n = 0; + val = ""; + } + + n = strtol(val, &s, 0); + } + else + { + if (strncmp(option, "no", 2) == 0) + { + option += 2; + n = 0; + } + else + n = 1; + + s = ""; + } + + if (*s != '\0' && *s != '-' && (*s != 'x' || s == val)) + /* + * String value(s)... + */ + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val); + else if (val != NULL) + { + /* + * Numeric value, range, or resolution... + */ + + if (*s == '-') + { + n2 = strtol(s + 1, NULL, 0); + ippAddRange(request, IPP_TAG_JOB, option, n, n2); + } + else if (*s == 'x') + { + n2 = strtol(s + 1, &s, 0); + + if (strcmp(s, "dpc") == 0) + ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_CM, n, n2); + else if (strcmp(s, "dpi") == 0) + ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_INCH, n, n2); + else + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val); + } + else + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, option, n); + } + else + /* + * Boolean value... + */ + ippAddBoolean(request, IPP_TAG_JOB, option, (char)n); + } + + /* + * Now fill in the HTTP request stuff... + */ + + httpClearFields(http); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); + httpEncode64(password, username); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, password); + + if (fp != stdin) + { + sprintf(buffer, "%u", ippLength(request) + (size_t)fileinfo.st_size); + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, buffer); + } + else + httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); + + /* + * Do the request... + */ + + for (;;) + { + /* + * POST the request, retrying as needed... + */ + + if (httpPost(http, resource)) + { + fputs("INFO: Unable to POST print request; retrying...\n", stderr); + sleep(10); + httpReconnect(http); + continue; + } + + fputs("INFO: POST successful, sending IPP request...\n", stderr); + + /* + * Send the IPP request... + */ + + request->state = IPP_IDLE; + + if (ippWrite(http, request) == IPP_ERROR) + { + fputs("ERROR: Unable to send IPP request!\n", stderr); + status = HTTP_ERROR; + break; + } + + fputs("INFO: IPP request sent, sending print file...\n", stderr); + + /* + * Then send the file... + */ + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + tbytes += nbytes; + fprintf(stderr, "INFO: Sending print file, %uk...\n", tbytes / 1024); + + if (httpWrite(http, buffer, nbytes) < nbytes) + { + perror("ERROR: Unable to send print file to printer"); + status = HTTP_ERROR; + break; + } + } + + /* + * If we are chunking the output from stdin, make sure we end up with + * a 0-length chunk at the end... + */ + + if (fp == stdin) + httpWrite(http, buffer, 0); + + fputs("INFO: Print file sent; checking status...\n", stderr); + + /* + * Finally, check the status from the HTTP server... + */ + + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + + if (status == HTTP_OK) + { + response = ippNew(); + ippRead(http, response); + + if (response->request.status.status_code > IPP_OK_CONFLICT) + fprintf(stderr, "ERROR: Print file was not accepted (%04x)!\n", + response->request.status.status_code); + else if ((job_id = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) + fputs("INFO: Print file accepted - job ID unknown.\n", stderr); + else + fprintf(stderr, "INFO: Print file accepted - job ID %d.\n", + job_id->values[0].integer); + } + else + { + response = NULL; + httpFlush(http); + + fprintf(stderr, "ERROR: Print request was not accepted (%d)!\n", status); + } + + break; + } + + /* + * Free memory... + */ + + httpClose(http); + if (request != NULL) + ippDelete(request); + if (response != NULL) + ippDelete(response); + + /* + * Close the print file as needed... + */ + + if (fp != stdin) + fclose(fp); + + /* + * Return the queue status... + */ + + return (status != HTTP_OK); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/lpd.c b/backend/lpd.c new file mode 100644 index 0000000000..3fa4175642 --- /dev/null +++ b/backend/lpd.c @@ -0,0 +1,393 @@ +/* + * "$Id$" + * + * Line Printer Daemon backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the printer or server. + * lpd_command() - Send an LPR command sequence and wait for a reply. + * lpd_queue() - Queue a file using the Line Printer Daemon protocol. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + +extern int rresvport(int *port); /* Hello? No prototype for this... */ + + +/* + * Local functions... + */ + +static int lpd_command(int lpd_fd, char *format, ...); +static int lpd_queue(char *hostname, char *printer, char *filename, + char *user, int copies); + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (printer name) */ + filename[1024]; /* File to print */ + int port; /* Port number (not used) */ + int status; /* Status of LPD job */ + + + if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, copy stdin to a temporary file and print the temporary + * file. + */ + + if (argc == 6) + { + /* + * Copy stdin to a temporary file... + */ + + FILE *fp; /* Temporary file */ + char buffer[8192]; /* Buffer for copying */ + int bytes; /* Number of bytes read */ + + + if ((fp = fopen(cupsTempFile(filename, sizeof(filename)), "w")) == NULL) + { + perror("ERROR: unable to create temporary file"); + return (1); + } + + while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) + if (fwrite(buffer, 1, bytes, fp) < bytes) + { + perror("ERROR: unable to write to temporary file"); + fclose(fp); + unlink(filename); + return (1); + } + + fclose(fp); + } + else + strcpy(filename, argv[6]); + + /* + * Extract the hostname and printer name from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * Queue the job... + */ + + status = lpd_queue(hostname, resource + 1, filename, + argv[2] /* user */, atoi(argv[4]) /* copies */); + + /* + * Remove the temporary file if necessary... + */ + + if (argc < 7) + unlink(filename); + + /* + * Return the queue status... + */ + + return (status); +} + + +/* + * 'lpd_command()' - Send an LPR command sequence and wait for a reply. + */ + +static int /* O - Status of command */ +lpd_command(int fd, /* I - Socket connection to LPD host */ + char *format, /* I - printf()-style format string */ + ...) /* I - Additional args as necessary */ +{ + va_list ap; /* Argument pointer */ + char buf[1024]; /* Output buffer */ + int bytes; /* Number of bytes to output */ + char status; /* Status from command */ + + + /* + * Format the string... + */ + + va_start(ap, format); + bytes = vsprintf(buf, format, ap); + va_end(ap); + + fprintf(stderr, "DEBUG: lpd_command %02.2x %s", buf[0], buf + 1); + + /* + * Send the command... + */ + + if (send(fd, buf, bytes, 0) < bytes) + return (-1); + + /* + * Read back the status from the command and return it... + */ + + if (recv(fd, &status, 1, 0) < 1) + return (-1); + + fprintf(stderr, "DEBUG: lpd_command returning %d\n", status); + + return (status); +} + + +/* + * 'lpd_queue()' - Queue a file using the Line Printer Daemon protocol. + */ + +static int /* O - Zero on success, non-zero on failure */ +lpd_queue(char *hostname, /* I - Host to connect to */ + char *printer, /* I - Printer/queue name */ + char *filename, /* I - File to print */ + char *user, /* I - Requesting user */ + int copies) /* I - Number of copies */ +{ + FILE *fp; /* Job file */ + char localhost[255]; /* Local host name */ + int error; /* Error number */ + struct stat filestats; /* File statistics */ + int port; /* LPD connection port */ + int fd; /* LPD socket */ + char control[10240], /* LPD control 'file' */ + *cptr; /* Pointer into control file string */ + char status; /* Status byte from command */ + struct sockaddr_in addr; /* Socket address */ + struct hostent *hostaddr; /* Host address */ + size_t nbytes, /* Number of bytes written */ + tbytes; /* Total bytes written */ + char buffer[8192]; /* Output buffer */ + + + /* + * First try to reserve a port for this connection... + */ + + if ((hostaddr = gethostbyname(hostname)) == NULL) + { + fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s", + hostname, strerror(errno)); + return (1); + } + + fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n", + hostname, printer); + + memset(&addr, 0, sizeof(addr)); + memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length); + addr.sin_family = hostaddr->h_addrtype; + addr.sin_port = htons(515); /* LPD/printer service */ + + for (port = 732;;) + { + if ((fd = rresvport(&port)) < 0) + { + perror("ERROR: Unable to connect to printer"); + return (1); + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + error = errno; + close(fd); + fd = -1; + + if (error == ECONNREFUSED) + { + fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...", + hostname); + sleep(30); + } + else if (error == EADDRINUSE) + { + port --; + if (port < 721) + port = 732; + } + else + { + perror("ERROR: Unable to connect to printer"); + return (1); + } + } + else + break; + } + + /* + * Next, open the print file and figure out its size... + */ + + if (stat(filename, &filestats)) + { + perror("ERROR: unable to stat print file"); + return (1); + } + + if ((fp = fopen(filename, "rb")) == NULL) + { + perror("ERROR: unable to open print file for reading"); + return (1); + } + + /* + * Send a job header to the printer, specifying no banner page and + * literal output... + */ + + lpd_command(fd, "\002%s\n", printer); /* Receive print job(s) */ + + gethostname(localhost, sizeof(localhost)); + localhost[31] = '\0'; /* RFC 1179, Section 7.2 - host name < 32 chars */ + + sprintf(control, "H%s\nP%s\n", localhost, user); + cptr = control + strlen(control); + + while (copies > 0) + { + sprintf(cptr, "ldfA%03.3d%s\n", getpid() % 1000, localhost); + cptr += strlen(cptr); + copies --; + } + + sprintf(cptr, "UdfA%03.3d%s\nNdfA%03.3d%s\n", + getpid() % 1000, localhost, + getpid() % 1000, localhost); + + fprintf(stderr, "DEBUG: Control file is:\n%s", control); + + lpd_command(fd, "\002%d cfA%03.3d%s\n", strlen(control), getpid() % 1000, + localhost); + + fprintf(stderr, "INFO: Sending control file (%d bytes)\n", strlen(control)); + + if (send(fd, control, strlen(control) + 1, 0) < (strlen(control) + 1)) + { + perror("ERROR: Unable to write control file"); + status = 1; + } + else if (read(fd, &status, 1) < 1 || status != 0) + fprintf(stderr, "ERROR: Remote host did not accept control file (%d)\n", + status); + else + { + /* + * Send the print file... + */ + + fputs("INFO: Control file sent successfully\n", stderr); + + lpd_command(fd, "\003%u dfA%03.3d%s\n", (unsigned)filestats.st_size, + getpid() % 1000, localhost); + + fprintf(stderr, "INFO: Sending data file (%u bytes)\n", + (unsigned)filestats.st_size); + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + fprintf(stderr, "INFO: Spooling LPR job, %u%% complete...\n", + (unsigned)(100 * tbytes / filestats.st_size)); + + if (send(fd, buffer, nbytes, 0) < nbytes) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + else + tbytes += nbytes; + } + + send(fd, "", 1, 0); + + if (tbytes < filestats.st_size) + status = 1; + else if (recv(fd, &status, 1, 0) < 1 || status != 0) + fprintf(stderr, "ERROR: Remote host did not accept data file (%d)\n", + status); + else + fputs("INFO: Data file sent successfully\n", stderr); + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + fclose(fp); + + return (status); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/parallel.c b/backend/parallel.c new file mode 100644 index 0000000000..df74637e62 --- /dev/null +++ b/backend/parallel.c @@ -0,0 +1,179 @@ +/* + * "$Id$" + * + * Parallel port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the specified parallel port. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'main()' - Send a file to the specified parallel port. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (device and options) */ + *options; /* Pointer to options */ + int port; /* Port number (not used) */ + FILE *fp; /* Print file */ + int fd; /* Parallel device */ + int error; /* Error code (if any) */ + size_t nbytes, /* Number of bytes written */ + tbytes; /* Total number of bytes written */ + char buffer[8192]; /* Output buffer */ + struct termios opts; /* Parallel port options */ + + + if (argc < 6 || argc > 7) + { + fputs("Usage: parallel job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + fp = stdin; + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * See if there are any options... + */ + + if ((options = strchr(resource, '?')) != NULL) + { + /* + * Yup, terminate the device name string and move to the first + * character of the options... + */ + + *options++ = '\0'; + } + + /* + * Open the parallel port device... + */ + + if ((fd = open(resource, O_WRONLY)) == -1) + { + perror("ERROR: Unable to open parallel port device file"); + return (1); + } + + /* + * Set any options provided... + */ + + tcgetattr(fd, &opts); + + opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */ + + /**** No options supported yet ****/ + + tcsetattr(fd, TCSANOW, &opts); + + /* + * Finally, send the print file... + */ + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + /* + * Write the print data to the printer... + */ + + if (write(fd, buffer, nbytes) < nbytes) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + else + tbytes += nbytes; + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes); + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/serial.c b/backend/serial.c new file mode 100644 index 0000000000..d9edfe2a2f --- /dev/null +++ b/backend/serial.c @@ -0,0 +1,297 @@ +/* + * "$Id$" + * + * Serial port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send a file to the printer or server. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (device and options) */ + *options, /* Pointer to options */ + name[255], /* Name of option */ + value[255], /* Value of option */ + *ptr; /* Pointer into name or value */ + int port; /* Port number (not used) */ + FILE *fp; /* Print file */ + int fd; /* Parallel device */ + int error; /* Error code (if any) */ + size_t nbytes, /* Number of bytes written */ + tbytes; /* Total number of bytes written */ + char buffer[8192]; /* Output buffer */ + struct termios opts; /* Parallel port options */ + + + if (argc < 6 || argc > 7) + { + fputs("Usage: serial job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + fp = stdin; + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * See if there are any options... + */ + + if ((options = strchr(resource, '?')) != NULL) + { + /* + * Yup, terminate the device name string and move to the first + * character of the options... + */ + + *options++ = '\0'; + } + + /* + * Open the parallel port device... + */ + + if ((fd = open(resource, O_WRONLY)) == -1) + { + perror("ERROR: Unable to open serial port device file"); + return (1); + } + + /* + * Set any options provided... + */ + + tcgetattr(fd, &opts); + + opts.c_lflag &= ~(ICANON | ECHO | ISIG); /* Raw mode */ + + if (options != NULL) + while (*options) + { + /* + * Get the name... + */ + + for (ptr = name; *options && *options != '=';) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '=') + { + /* + * Get the value... + */ + + options ++; + + for (ptr = value; *options && *options != '+';) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '+') + options ++; + } + else + value[0] = '\0'; + + /* + * Process the option... + */ + + if (strcasecmp(name, "baud") == 0) + { + /* + * Set the baud rate... + */ + +#if B19200 == 19200 + cfsetispeed(&opts, atoi(value)); + cfsetospeed(&opts, atoi(value)); +#else + switch (atoi(value)) + { + case 1200 : + cfsetispeed(&opts, B1200); + cfsetospeed(&opts, B1200); + break; + case 2400 : + cfsetispeed(&opts, B2400); + cfsetospeed(&opts, B2400); + break; + case 4800 : + cfsetispeed(&opts, B4800); + cfsetospeed(&opts, B4800); + break; + case 9600 : + cfsetispeed(&opts, B9600); + cfsetospeed(&opts, B9600); + break; + case 19200 : + cfsetispeed(&opts, B19200); + cfsetospeed(&opts, B19200); + break; + case 38400 : + cfsetispeed(&opts, B38400); + cfsetospeed(&opts, B38400); + break; + default : + fprintf(stderr, "WARNING: Unsupported baud rate %s!\n", value); + break; + } +#endif /* B19200 == 19200 */ + } + else if (strcasecmp(name, "bits") == 0) + { + /* + * Set number of data bits... + */ + + switch (atoi(value)) + { + case 7 : + opts.c_cflag &= ~CSIZE; + opts.c_cflag |= CS7; + opts.c_cflag |= PARENB; + opts.c_cflag &= ~PARODD; + break; + case 8 : + opts.c_cflag &= ~CSIZE; + opts.c_cflag |= CS8; + opts.c_cflag &= ~PARENB; + break; + } + } + else if (strcasecmp(name, "parity") == 0) + { + /* + * Set parity checking... + */ + + if (strcasecmp(value, "even") == 0) + { + opts.c_cflag |= PARENB; + opts.c_cflag &= ~PARODD; + } + else if (strcasecmp(value, "odd") == 0) + { + opts.c_cflag |= PARENB; + opts.c_cflag |= PARODD; + } + else if (strcasecmp(value, "none") == 0) + opts.c_cflag &= ~PARENB; + } + } + + tcsetattr(fd, TCSANOW, &opts); + + /* + * Finally, send the print file... + */ + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + /* + * Write the print data to the printer... + */ + + if (write(fd, buffer, nbytes) < nbytes) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + else + tbytes += nbytes; + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes); + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/smb.sh b/backend/smb.sh new file mode 100755 index 0000000000..a0c67aecb3 --- /dev/null +++ b/backend/smb.sh @@ -0,0 +1,88 @@ +#!/bin/sh +# +# "$Id$" +# +# SMB printing script for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44145 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +SMBCLIENT=/usr/local/samba/bin/smbclient + +# +# Usage: +# +# printer job user title copies options [filename] +# + +if [ $# -lt 5 -o $# -gt 6 ]; then + # Too few or too many arguments + echo 'Usage: smb job-id user title copies options [file]' >&2 + exit 1 +fi + +# +# If "filename" is not on the command-line, then we read the print +# data from stdin and write it to a temporary file. +# + +if [ $# = 5 ]; then + # Collect all print data and put it in a temporary file... + if [ "$TMPDIR" = "" ]; then + TMPDIR=/var/tmp + fi + + filename="$TMPDIR/$$.smb" + cat >$filename +else + # Use the file on the command-line... + filename="$6" +fi + +# +# Take apart the URI in $0... +# + +uri="$0" +host=`echo $uri | awk -F/ '{print substr($3, index($3, "@") + 1)}'` +user=`echo $uri | awk -F/ '{print substr($3, 0, index($3, "@") - 1)}'` +if [ "$user" != "" ]; then + user="-U $user" +fi +printer=`echo $uri | awk -F/ '{print $4}'` + +# +# Send the file to the remote system... +# + +$SMBCLIENT //$host/$printer $user -P -N < +#include +#include +#include +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'main()' - Send a file to the printer or server. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024]; /* Resource info (not used) */ + FILE *fp; /* Print file */ + int port; /* Port number */ + int fd; /* AppSocket */ + int error; /* Error code (if any) */ + struct sockaddr_in addr; /* Socket address */ + struct hostent *hostaddr; /* Host address */ + int wbytes; /* Number of bytes written */ + size_t nbytes, /* Number of bytes read */ + tbytes; /* Total number of bytes written */ + char buffer[8192], /* Output buffer */ + *bufptr; /* Pointer into buffer */ + struct timeval timeout; /* Timeout for select() */ + fd_set input; /* Input set for select() */ + + + if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + fp = stdin; + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + } + + /* + * Extract the hostname and port number from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + if (port == 0) + port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */ + + /* + * Then try to connect to the remote host... + */ + + if ((hostaddr = gethostbyname(hostname)) == NULL) + { + fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s", + hostname, strerror(errno)); + return (1); + } + + fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n", + hostname, port); + + memset(&addr, 0, sizeof(addr)); + memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length); + addr.sin_family = hostaddr->h_addrtype; + addr.sin_port = htons(port); + + for (;;) + { + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + perror("ERROR: Unable to connect to printer"); + return (1); + } + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + error = errno; + close(fd); + fd = -1; + + if (error == ECONNREFUSED) + { + fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...\n", + hostname); + sleep(30); + } + else + { + perror("ERROR: Unable to connect to printer"); + return (1); + } + } + else + break; + } + + /* + * Finally, send the print file... + */ + + fputs("INFO: Connected to host, sending print job...\n", stderr); + + tbytes = 0; + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + + /* + * Check for possible data coming back from the printer... + */ + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + FD_ZERO(&input); + FD_SET(fd, &input); + if (select(fd + 1, &input, NULL, NULL, &timeout) > 0) + { + /* + * Grab the data coming back and spit it out to stderr... + */ + + if ((nbytes = recv(fd, buffer, sizeof(buffer), 0)) > 0) + fprintf(stderr, "INFO: Received %u bytes of back-channel data!\n", + nbytes); + } + else if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes); + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/Makefile b/berkeley/Makefile new file mode 100644 index 0000000000..5ffc54ab2a --- /dev/null +++ b/berkeley/Makefile @@ -0,0 +1,95 @@ +# +# "$Id$" +# +# Berkeley commands makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +TARGETS = lpc lpq lpr lprm +OBJS = lpc.o lpq.o lpr.o lprm.o + +# +# Make all targets... +# + +all: $(TARGETS) + +# +# Clean all object files... +# + +clean: + rm -f $(OBJS) $(TARGETS) + +# +# Install all targets... +# + +install: + -$(MKDIR) $(BINDIR) + -$(MKDIR) $(SBINDIR) + $(CP) lpq lpr lprm $(BINDIR) + $(CP) lpc $(SBINDIR) + +# +# lpc +# + +lpc: lpc.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpc lpc.o $(LIBS) + +lpc.o: ../cups/cups.h ../Makedefs + +# +# lpq +# + +lpq: lpq.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpq lpq.o $(LIBS) + +lpq.o: ../cups/cups.h ../Makedefs + +# +# lpr +# + +lpr: lpr.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpr lpr.o $(LIBS) + +lpr.o: ../cups/cups.h ../Makedefs + +# +# lprm +# + +lprm: lprm.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lprm lprm.o $(LIBS) + +lprm.o: ../cups/cups.h ../Makedefs + +# +# End of "$Id$". +# diff --git a/berkeley/lpc.c b/berkeley/lpc.c new file mode 100644 index 0000000000..cf2fc33423 --- /dev/null +++ b/berkeley/lpc.c @@ -0,0 +1,458 @@ +/* + * "$Id$" + * + * "lpc" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and commands. + * compare_strings() - Compare two command-line strings. + * do_command() - Do an lpc command... + * show_help() - Show help messages. + * show_status() - Show printers. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static int compare_strings(char *, char *, int); +static void do_command(http_t *, char *, char *); +static void show_help(char *); +static void show_status(http_t *, char *); + + +/* + * 'main()' - Parse options and commands. + */ + +int +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + http_t *http; /* Connection to server */ + char line[1024], /* Input line from user */ + *params; /* Pointer to parameters */ + + + /* + * Connect to the scheduler... + */ + + http = httpConnect(cupsServer(), ippPort()); + + if (argc > 1) + { + /* + * Process a single command on the command-line... + */ + + do_command(http, argv[1], argv[2]); + } + else + { + /* + * Do the command prompt thing... + */ + + printf("lpc> "); + while (fgets(line, sizeof(line), stdin) != NULL) + { + /* + * Strip the trailing newline... + */ + + line[strlen(line) - 1] = '\0'; + + /* + * Find any options in the string... + */ + + while (isspace(line[0])) + strcpy(line, line + 1); + + for (params = line; *params != '\0'; params ++) + if (isspace(*params)) + break; + + /* + * Remove whitespace between the command and parameters... + */ + + while (isspace(*params)) + *params++ = '\0'; + + /* + * The "quit" and "exit" commands exit; otherwise, process as needed... + */ + + if (compare_strings(line, "quit", 1) == 0 || + compare_strings(line, "exit", 2) == 0) + break; + + if (*params == '\0') + do_command(http, line, NULL); + else + do_command(http, line, params); + + /* + * Put another prompt out to the user... + */ + + printf("lpc> "); + } + } + + /* + * Close the connection to the server and return... + */ + + httpClose(http); + + return (0); +} + + +/* + * 'compare_strings()' - Compare two command-line strings. + */ + +static int /* O - -1 or 1 = no match, 0 = match */ +compare_strings(char *s, /* I - Command-line string */ + char *t, /* I - Option string */ + int tmin) /* I - Minimum number of unique chars in option */ +{ + int slen; /* Length of command-line string */ + + + slen = strlen(s); + if (slen < tmin) + return (-1); + else + return (strncmp(s, t, slen)); +} + + +/* + * 'do_command()' - Do an lpc command... + */ + +static void +do_command(http_t *http, /* I - HTTP connection to server */ + char *command, /* I - Command string */ + char *params) /* I - Parameters for command */ +{ + if (compare_strings(command, "status", 4) == 0) + show_status(http, params); + else if (compare_strings(command, "help", 1) == 0 || + strcmp(command, "?") == 0) + show_help(params); + else + puts("?Invalid command"); +} + + +/* + * 'show_help()' - Show help messages. + */ + +static void +show_help(char *command) /* I - Command to describe or NULL */ +{ + if (command == NULL) + { + puts("Commands may be abbreviated. Commands are:"); + puts(""); + puts("exit help quit status ?"); + } + else if (compare_strings(command, "help", 1) == 0 || + strcmp(command, "?") == 0) + puts("help\t\tget help on commands"); + else if (compare_strings(command, "status", 4) == 0) + puts("status\t\tshow status of daemon and queue"); + else + puts("?Invalid help command unknown"); +} + + +/* + * 'show_status()' - Show printers. + */ + +static void +show_status(http_t *http, /* I - HTTP connection to server */ + char *dests) /* I - Destinations */ +{ + ipp_t *request, /* IPP Request */ + *response, /* IPP Response */ + *jobs; /* IPP Get Jobs response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + char *printer, /* Printer name */ + *device; /* Device URI */ + ipp_pstate_t pstate; /* Printer state */ + int accepting; /* Is printer accepting jobs? */ + int jobcount; /* Count of current jobs */ + char *dptr, /* Pointer into destination list */ + *ptr; /* Pointer into printer name */ + int match; /* Non-zero if this job matches */ + char printer_uri[HTTP_MAX_URI]; + /* Printer URI */ + + + DEBUG_printf(("show_status(%08x, %08x)\n", http, dests)); + + if (http == NULL) + return; + + /* + * Build a CUPS_GET_PRINTERS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PRINTERS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + attr = ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + attr = ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/printers/")) != NULL) + { + DEBUG_puts("show_status: request succeeded..."); + + /* + * Loop through the printers returned in the list and display + * their status... + */ + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this job... + */ + + printer = NULL; + device = "file:/dev/null"; + pstate = IPP_PRINTER_IDLE; + jobcount = 0; + accepting = 1; + + while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) + { + if (strcmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + printer = attr->values[0].string.text; + + if (strcmp(attr->name, "device-uri") == 0 && + attr->value_tag == IPP_TAG_URI) + device = attr->values[0].string.text; + + if (strcmp(attr->name, "printer-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + pstate = (ipp_pstate_t)attr->values[0].integer; + + if (strcmp(attr->name, "printer-is-accepting-jobs") == 0 && + attr->value_tag == IPP_TAG_BOOLEAN) + accepting = attr->values[0].boolean; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (printer == NULL) + { + if (attr == NULL) + break; + else + continue; + } + + /* + * See if this is a printer we're interested in... + */ + + match = dests == NULL; + + if (dests != NULL) + { + for (dptr = dests; *dptr != '\0';) + { + /* + * Skip leading whitespace and commas... + */ + + while (isspace(*dptr) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Compare names... + */ + + for (ptr = printer; + *ptr != '\0' && *dptr != '\0' && *ptr == *dptr; + ptr ++, dptr ++); + + if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' || isspace(*dptr))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr) && *dptr != '\0') + dptr ++; + while (isspace(*dptr) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + } + } + + /* + * Display the printer entry if needed... + */ + + if (match) + { + /* + * If the printer state is "IPP_PRINTER_PROCESSING", then grab the + * current job for the printer. + */ + + if (pstate == IPP_PRINTER_PROCESSING) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * limit + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOBS; + 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); + + sprintf(printer_uri, "ipp://localhost/printers/%s", printer); + attr = ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, printer_uri); + + if ((jobs = cupsDoRequest(http, request, "/jobs/")) != NULL) + { + for (attr = jobs->attrs; attr != NULL; attr = attr->next) + if (strcmp(attr->name, "job-id") == 0) + jobcount ++; + + ippDelete(jobs); + } + } + + /* + * Display it... + */ + + printf("%s:\n", printer); + if (strncmp(device, "file:", 5) == 0) + printf("\tprinter is on device \'%s\' speed -1\n", device + 5); + else + printf("\tprinter is on device \'%s\' speed -1\n", device); + printf("\tqueuing is %sabled\n", accepting ? "en" : "dis"); + printf("\tprinting is %sabled\n", + pstate == IPP_PRINTER_STOPPED ? "dis" : "en"); + if (jobcount == 0) + puts("\tno entries"); + else + printf("\t%d entries\n", jobcount); + puts("\tdaemon present"); + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lpq.c b/berkeley/lpq.c new file mode 100644 index 0000000000..55bf7ed6a4 --- /dev/null +++ b/berkeley/lpq.c @@ -0,0 +1,369 @@ +/* + * "$Id$" + * + * "lpq" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and commands. + * show_jobs() - Show jobs. + */ + +/* + * Include necessary headers... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static int show_jobs(http_t *, const char *, const char *, const int, + const int); + + +/* + * 'main()' - Parse options and commands. + */ + +int +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + http_t *http; /* Connection to server */ + const char *dest, /* Desired printer */ + *user; /* Desired user */ + int id, /* Desired job ID */ + interval, /* Reporting interval */ + longstatus; /* Show file details */ + + /* + * Connect to the scheduler... + */ + + http = httpConnect(cupsServer(), ippPort()); + + /* + * Check for command-line options... + */ + + dest = cupsGetDefault(); + user = NULL; + id = 0; + interval = 0; + longstatus = 0; + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '+') + interval = atoi(argv[i] + 1); + else if (argv[i][0] == '-') + { + switch (argv[i][1]) + { + case 'P' : /* Printer */ + if (argv[i][2]) + dest = argv[i] + 2; + else + { + i ++; + dest = argv[i]; + } + break; + + case 'l' : /* Long status */ + longstatus = 1; + break; + + default : + fputs("Usage: lpq [-P dest] [-l] [+interval]\n", stderr); + return (1); + } + } + else if (isdigit(argv[i][0])) + id = atoi(argv[i]); + else + user = argv[i]; + + /* + * Show the status in a loop... + */ + + for (;;) + { + i = show_jobs(http, dest, user, id, longstatus); + + if (i && interval) + sleep(interval); + else + break; + } + + /* + * Close the connection to the server and return... + */ + + httpClose(http); + + return (0); +} + + +/* + * 'show_jobs()' - Show jobs. + */ + +static int /* O - Number of jobs in queue */ +show_jobs(http_t *http, /* I - HTTP connection to server */ + const char *dest, /* I - Destination */ + const char *user, /* I - User */ + const int id, /* I - Job ID */ + const int longstatus)/* I - 1 if long report desired */ +{ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + const char *jobdest, /* Pointer into job-printer-uri */ + *jobuser, /* Pointer to job-originating-user-name */ + *jobname; /* Pointer to job-name */ + ipp_jstate_t jobstate; /* job-state */ + int jobid, /* job-id */ + jobsize, /* job-k-octets */ + jobpriority, /* job-priority */ + jobcount, /* Number of jobs */ + rank; /* Rank of job */ + char resource[1024]; /* Resource string */ + static const char *ranks[10] =/* Ranking strings */ + { + "th", + "st", + "nd", + "rd", + "th", + "th", + "th", + "th", + "th", + "th" + }; + + + DEBUG_printf(("show_jobs(%08x, %08x, %08x, %d, %d)\n", http, dest, user, id, + longstatus)); + + if (http == NULL) + return (0); + + /* + * Build an IPP_GET_JOBS or IPP_GET_JOB_ATTRIBUTES request, which requires + * the following attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri or printer-uri + * [ + */ + + request = ippNew(); + + request->request.op.operation_id = id ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + attr = ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + attr = ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + if (dest == NULL) + { + if (id) + sprintf(resource, "ipp://localhost/jobs/%d", id); + else + strcpy(resource, "ipp://localhost/jobs"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", + NULL, resource); + } + else + { + sprintf(resource, "ipp://localhost/printers/%s", dest); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", + NULL, resource); + } + + if (user) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user); + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + } + + /* + * Do the request and get back a response... + */ + + if (!longstatus) + puts("Rank\tPri Owner Job Files Total Size"); + + jobcount = 0; + + if ((response = cupsDoRequest(http, request, "/jobs/")) != NULL) + { + rank = 1; + + /* + * Loop through the job list and display them... + */ + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this job... + */ + + jobid = 0; + jobsize = 0; + jobpriority = 50; + jobstate = IPP_JOB_PENDING; + jobname = "untitled"; + jobuser = NULL; + jobdest = NULL; + + while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + { + if (strcmp(attr->name, "job-id") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobid = attr->values[0].integer; + + if (strcmp(attr->name, "job-k-octets") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobsize = attr->values[0].integer * 1024; + + if (strcmp(attr->name, "job-priority") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobpriority = attr->values[0].integer; + + if (strcmp(attr->name, "job-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + jobstate = (ipp_jstate_t)attr->values[0].integer; + + if (strcmp(attr->name, "job-printer-uri") == 0 && + attr->value_tag == IPP_TAG_URI) + if ((jobdest = strrchr(attr->values[0].string.text, '/')) != NULL) + jobdest ++; + + if (strcmp(attr->name, "job-originating-user-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + jobuser = attr->values[0].string.text; + + if (strcmp(attr->name, "job-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + jobname = attr->values[0].string.text; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (jobdest == NULL || jobid == 0) + { + if (attr == NULL) + break; + else + continue; + } + + jobcount ++; + + /* + * Display the job... + */ + + if (longstatus) + { + puts(""); + + if (jobstate == IPP_JOB_PROCESSING) + printf("%s: active\t\t\t\t ", jobuser); + else + { + printf("%s: %d%s\t\t\t\t ", jobuser, rank, ranks[rank % 10]); + rank ++; + } + + printf("[job %03dlocalhost]\n", jobid); + printf("\t%-33s%d bytes\n", jobname, jobsize); + } + else + { + if (jobstate == IPP_JOB_PROCESSING) + printf("active\t"); + else + { + printf("%d%s\t", rank, ranks[rank % 10]); + rank ++; + } + + printf(" %-5d%-7.7s%-7d%-19s%d bytes\n", jobpriority, jobuser, jobid, + jobname, jobsize); + } + if (attr == NULL) + break; + } + + ippDelete(response); + } + + return (jobcount); +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lpr.c b/berkeley/lpr.c new file mode 100644 index 0000000000..f209efee6d --- /dev/null +++ b/berkeley/lpr.c @@ -0,0 +1,252 @@ +/* + * "$Id$" + * + * "lpr" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and send files for printing. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + + +/* + * 'main()' - Parse options and send files for printing. + */ + +int +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + int job_id; /* Job ID */ + const char *dest; /* Destination printer */ + const char *title; /* Job title */ + int priority; /* Job priority (1-100) */ + int num_copies; /* Number of copies per file */ + int num_files; /* Number of files printed */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ + int silent, /* Silent or verbose output? */ + deletefile; /* Delete file after print? */ + char tempfile[1024]; /* Temporary file for printing from stdin */ + char buffer[8192]; /* Copy buffer */ + FILE *temp; /* Temporary file pointer */ + + + silent = 0; + deletefile = 0; + dest = cupsGetDefault(); + num_options = 0; + options = NULL; + num_files = 0; + title = NULL; + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-') + switch (argv[i][1]) + { + case 'i' : /* indent */ + case 'w' : /* width */ + if (argv[i][2] == '\0') + i ++; + case 'c' : /* CIFPLOT */ + case 'd' : /* DVI */ + case 'f' : /* FORTRAN */ + case 'g' : /* plot */ + case 'n' : /* Ditroff */ + case 't' : /* Troff */ + case 'v' : /* Raster image */ + fprintf(stderr, "Warning: \'%c\' format modifier not supported - output may not be correct!\n", + argv[i][1]); + break; + + case 'o' : /* Option */ + if (argv[i][2] != '\0') + num_options = cupsParseOptions(argv[i] + 2, num_options, &options); + else + { + i ++; + num_options = cupsParseOptions(argv[i], num_options, &options); + } + break; + + case 'l' : /* Literal/raw */ + num_options = cupsParseOptions("raw", num_options, &options); + break; + + case 'p' : /* Prettyprint */ + num_options = cupsParseOptions("prettyprint", num_options, &options); + break; + + case 'h' : /* Suppress burst page */ + case 's' : /* Don't use symlinks */ + break; + + case 'm' : /* Mail on completion */ + fputs("Warning: email notification is not supported!\n", stderr); + break; + + case 'r' : /* Remove file after printing */ + deletefile = 1; + break; + + case 'P' : /* Destination printer or class */ + if (argv[i][2] != '\0') + dest = argv[i] + 2; + else + { + i ++; + dest = argv[i]; + } + break; + + case '#' : /* Number of copies */ + if (argv[i][2] != '\0') + num_copies = atoi(argv[i] + 2); + else + { + i ++; + num_copies = atoi(argv[i]); + } + + if (num_copies < 1 || num_copies > 100) + { + fputs("lpr: Number copies must be between 1 and 100.\n", stderr); + return (1); + } + + sprintf(buffer, "%d", num_copies); + num_options = cupsAddOption("copies", buffer, num_options, &options); + break; + + case 'C' : /* Class */ + case 'J' : /* Job name */ + case 'T' : /* Title */ + if (argv[i][2] != '\0') + title = argv[i] + 2; + else + { + i ++; + title = argv[i]; + } + break; + + default : + fprintf(stderr, "lpr: Unknown option \'%c\'!\n", argv[i][1]); + return (1); + } + else + { + /* + * Print a file... + */ + + if (dest == NULL) + { + fputs("lpr: error - no default destination available.\n", stderr); + return (1); + } + + num_files ++; + if (title) + job_id = cupsPrintFile(dest, argv[i], title, num_options, options); + else + { + char *filename; + + if ((filename = strrchr(argv[i], '/')) != NULL) + filename ++; + else + filename = argv[i]; + + job_id = cupsPrintFile(dest, argv[i], filename, num_options, options); + } + + if (job_id < 1) + { + fprintf(stderr, "lpr: unable to print file \'%s\'.\n", argv[i]); + return (1); + } + else if (deletefile) + unlink(argv[i]); + } + + /* + * See if we printed anything; if not, print from stdin... + */ + + if (num_files == 0) + { + if (dest == NULL) + { + fputs("lpr: error - no default destination available.\n", stderr); + return (1); + } + + temp = fopen(cupsTempFile(tempfile, sizeof(tempfile)), "w"); + + if (temp == NULL) + { + fputs("lpr: unable to create temporary file.\n", stderr); + return (1); + } + + while ((i = fread(buffer, 1, sizeof(buffer), stdin)) > 0) + fwrite(buffer, 1, i, temp); + + i = ftell(temp); + fclose(temp); + + if (i == 0) + { + fputs("lpr: standard input is empty, so no job has been sent.\n", stderr); + return (1); + } + + if (title) + job_id = cupsPrintFile(dest, tempfile, title, num_options, options); + else + job_id = cupsPrintFile(dest, tempfile, "(stdin)", num_options, options); + + unlink(tempfile); + + if (job_id < 1) + { + fputs("lpr: unable to print standard input.\n", stderr); + return (1); + } + } + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lprm.c b/berkeley/lprm.c new file mode 100644 index 0000000000..2df9530c69 --- /dev/null +++ b/berkeley/lprm.c @@ -0,0 +1,205 @@ +/* + * "$Id$" + * + * "lprm" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and cancel jobs. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#include +#include + + +/* + * 'main()' - Parse options and cancel jobs. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + http_t *http; /* HTTP connection to server */ + int i; /* Looping var */ + int job_id; /* Job ID */ + const char *dest; /* Destination printer */ + char uri[1024]; /* Printer or job URI */ + ipp_t *request; /* IPP request */ + ipp_t *response; /* IPP response */ + ipp_op_t op; /* Operation */ + cups_lang_t *language; /* Language */ + + + /* + * Setup to cancel individual print jobs... + */ + + op = IPP_CANCEL_JOB; + job_id = 0; + dest = cupsGetDefault(); + response = NULL; + + /* + * Open a connection to the server... + */ + + if ((http = httpConnect(cupsServer(), ippPort())) == NULL) + { + fputs("lprm: Unable to contact server!\n", stderr); + return (1); + } + + /* + * Process command-line arguments... + */ + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-' && argv[i][1] != '\0') + switch (argv[i][1]) + { + case 'P' : /* Cancel jobs on a printer */ + if (argv[i][2]) + dest = argv[i] + 2; + else + { + i ++; + dest = argv[i]; + } + break; + + default : + fprintf(stderr, "lprm: Unknown option \'%c\'!\n", argv[i][1]); + return (1); + } + else + { + /* + * Cancel a job or printer... + */ + + if (isdigit(argv[i][0])) + { + dest = NULL; + op = IPP_CANCEL_JOB; + job_id = atoi(argv[i]); + } + else if (strcmp(argv[i], "-") == 0) + { + /* + * Cancel all jobs + */ + + op = IPP_PURGE_JOBS; + } + else + job_id = 0; + + /* + * Build an IPP request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + job-id *or* job-uri + * [requesting-user-name] + */ + + request = ippNew(); + + request->request.op.operation_id = op; + 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); + + if (dest) + { + sprintf(uri, "ipp://localhost/printers/%s", dest); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", + job_id); + } + else + { + sprintf(uri, "ipp://localhost/jobs/%d", job_id); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, + uri); + } + + /* + * Do the request and get back a response... + */ + + if (op == IPP_PURGE_JOBS) + response = cupsDoRequest(http, request, "/admin/"); + else + response = cupsDoRequest(http, request, "/jobs/"); + + if (response != NULL) + { + if (response->request.status.status_code == IPP_NOT_FOUND) + fputs("lprm: Job or printer not found!\n", stderr); + else if (response->request.status.status_code > IPP_OK_CONFLICT) + fputs("lprm: Unable to cancel job(s)!\n", stderr); + + ippDelete(response); + } + else + { + fputs("lprm: Unable to cancel job(s)!\n", stderr); + return (1); + } + } + + /* + * If nothing has been cancelled yet, cancel the current job on the specified + * (or default) printer... + */ + + if (response == NULL) + if (!cupsCancelJob(dest, 0)) + { + fputs("lprm: Unable to cancel job(s)!\n", stderr); + return (1); + } + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile new file mode 100644 index 0000000000..feffe13c71 --- /dev/null +++ b/cgi-bin/Makefile @@ -0,0 +1,83 @@ +# +# "$Id$" +# +# CGI makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +TARGETS = classes.cgi jobs.cgi printers.cgi +OBJS = classes.o jobs.o printers.o + +# +# Make all targets... +# + +all: $(TARGETS) + +# +# Clean all object files... +# + +clean: + rm -f $(OBJS) $(TARGETS) + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERROOT)/cgi-bin + $(CP) $(TARGETS) $(SERVERROOT)/cgi-bin + +# +# classes.cgi +# + +classes.cgi: classes.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ classes.o $(LIBS) + +$(OBJS): ../Makedefs ../cups/cups.h ../cups/ipp.h ../cups/language.h + +# +# jobs.cgi +# + +jobs.cgi: jobs.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ jobs.o $(LIBS) + +$(OBJS): ../Makedefs ../cups/cups.h ../cups/ipp.h ../cups/language.h + +# +# printers.cgi +# + +printers.cgi: printers.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ printers.o $(LIBS) + +$(OBJS): ../Makedefs ../cups/cups.h ../cups/ipp.h ../cups/language.h + +# +# End of "$Id$". +# diff --git a/cgi-bin/classes.c b/cgi-bin/classes.c new file mode 100644 index 0000000000..53a39e064f --- /dev/null +++ b/cgi-bin/classes.c @@ -0,0 +1,484 @@ +/* + * "$Id$" + * + * Class status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + * show_class_list() - Show a list of classes... + * show_class_info() - Show class information. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static void show_class_list(http_t *http, cups_lang_t *language); +static void show_class_info(http_t *http, cups_lang_t *language, + char *name); + + +/* + * 'main()' - Main entry for CGI. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Language information */ + char *name; /* Class name */ + http_t *http; /* Connection to the server */ + + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Tell the client to expect HTML... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + /* + * See if we need to show a list of classes or the status of a + * single class... + */ + + name = argv[0]; + if (strcmp(name, "/") == 0 || strcmp(name, "classes.cgi") == 0) + name = NULL; + + /* + * Print the standard header... + */ + + puts(""); + puts(""); + if (name) + puts(""); + else + puts(""); + printf("%s on %s - Common UNIX Printing System\n", + name == NULL ? "Classes" : name, getenv("SERVER_NAME")); + puts(""); + puts(""); + puts("\"Current"); + puts("\"Current"); + puts("\"Current"); + puts("\"Read"); +#ifdef ESPPRINTPRO + puts("\"Download"); + puts("\"Get"); +#else + puts("\"Download"); +#endif /* ESPPRINTPRO */ + puts(""); + puts(""); + puts(""); + puts("

"); + puts(""); + puts("\"Easy"); +#ifdef ESPPRINTPRO + puts(""); +#else + puts(""); +#endif /* ESPPRINTPRO */ + + printf("

%s on %s

\n", name == NULL ? "Classes" : name, + getenv("SERVER_NAME")); + fflush(stdout); + + puts("
"); + puts(""); + puts(""); + puts(""); + puts(""); + puts(""); + puts(""); + + /* + * Show the information... + */ + + if (name == NULL) + show_class_list(http, language); + else + show_class_info(http, language, name); + + /* + * Write a standard trailer... + */ + + puts("
NameStatusJobs
"); + puts("
"); + + puts("
"); + + puts("

The Common UNIX Printing System, CUPS, and the CUPS logo are the"); + puts("trademark property of Easy Software"); + puts("Products. CUPS is copyright 1997-1999 by Easy Software Products,"); + puts("All Rights Reserved."); + + puts(""); + puts(""); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'show_class_list()' - Show a list of classes... + */ + +static void +show_class_list(http_t *http, /* I - HTTP connection */ + cups_lang_t *language)/* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + + + /* + * Build a CUPS_GET_CLASSES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_CLASSES; + request->request.op.request_id = 1; + + + 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); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/classes/")) != NULL) + { + /* + * Loop through the classes returned in the list and display + * their devices... + */ + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Show the class status for each class... + */ + + while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) + { + if (strcmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + show_class_info(http, language, attr->values[0].string.text); + + attr = attr->next; + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } +} + + +/* + * 'show_class_info()' - Show class information. + */ + +static void +show_class_info(http_t *http, + cups_lang_t *language, + char *name) +{ + ipp_t *request, /* IPP request */ + *response, /* IPP response */ + *jobs; /* IPP Get Jobs response */ + int jobcount; /* Number of jobs */ + ipp_attribute_t *attr; /* IPP attribute */ + char *message; /* Printer state message */ + int accepting; /* Accepting requests? */ + ipp_pstate_t pstate; /* Printer state */ + char uri[HTTP_MAX_URI];/* Printer URI */ + + + /* + * Build a IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + 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); + + sprintf(uri, "ipp://localhost/classes/%s", name); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, uri + 15)) == NULL) + { + puts("

Unable to communicate with CUPS server!"); + return; + } + + if (response->request.status.status_code == IPP_NOT_FOUND) + { + puts("

Class does not exist."); + ippDelete(response); + return; + } + + /* + * Grab the needed class attributes... + */ + + if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) + pstate = (ipp_pstate_t)attr->values[0].integer; + else + pstate = IPP_PRINTER_IDLE; + + if ((attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT)) != NULL) + message = attr->values[0].string.text; + else + message = NULL; + + if ((attr = ippFindAttribute(response, "printer-is-accepting-jobs", + IPP_TAG_BOOLEAN)) != NULL) + accepting = attr->values[0].boolean; + else + accepting = 1; + + if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL) + { + strcpy(uri, "http:"); + strcpy(uri + 5, strchr(attr->values[0].string.text, '/')); + } + + /* + * Display the class entry... + */ + + puts(""); + + printf("%s\n", uri, name); + + puts(""); + + printf("%s: %s, %s
\n", + cupsLangString(language, CUPS_MSG_PRINTER_STATE), + cupsLangString(language, pstate == IPP_PRINTER_IDLE ? CUPS_MSG_IDLE : + pstate == IPP_PRINTER_PROCESSING ? + CUPS_MSG_PROCESSING : CUPS_MSG_STOPPED), + cupsLangString(language, accepting ? CUPS_MSG_ACCEPTING_JOBS : + CUPS_MSG_NOT_ACCEPTING_JOBS)); + + if (message) + printf("
\"%s\"\n", message); + else if (!accepting || pstate == IPP_PRINTER_STOPPED) + puts("
\"Reason Unknown\""); + + puts(""); + + /* + * Show a list of jobs as needed... + */ + + if (pstate != IPP_PRINTER_IDLE) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + 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); + + sprintf(uri, "ipp://localhost/printers/%s", name); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + jobs = cupsDoRequest(http, request, uri + 15); + } + else + jobs = NULL; + + puts(""); + jobcount = 0; + + if (jobs != NULL) + { + char *username; /* Pointer to job-originating-user-name */ + int jobid, /* job-id */ + size; /* job-k-octets */ + + + for (attr = jobs->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this job... + */ + + jobid = 0; + size = 0; + username = NULL; + + while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + { + if (strcmp(attr->name, "job-id") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobid = attr->values[0].integer; + + if (strcmp(attr->name, "job-k-octets") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + size = attr->values[0].integer; + + if (strcmp(attr->name, "job-originating-user-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + username = attr->values[0].string.text; + + attr = attr->next; + } + + /* + * Display the job if it matches the current class... + */ + + if (username != NULL) + { + jobcount ++; + printf("%s-%d %s %dk
\n", jobid, name, + jobid, username, size); + } + + if (attr == NULL) + break; + } + + ippDelete(jobs); + } + + if (jobcount == 0) + puts("None"); + puts(""); + puts(""); + + ippDelete(response); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/jobs.c b/cgi-bin/jobs.c new file mode 100644 index 0000000000..a0bb945bc2 --- /dev/null +++ b/cgi-bin/jobs.c @@ -0,0 +1,584 @@ +/* + * "$Id$" + * + * Job status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + * show_job_list() - Show a list of jobs... + * show_job_info() - Show job information. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static void show_job_list(http_t *http, cups_lang_t *language); +static void show_job_info(http_t *http, cups_lang_t *language, + char *name); + + +/* + * 'main()' - Main entry for CGI. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Language information */ + char *job; /* Job name */ + http_t *http; /* Connection to the server */ + + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Tell the client to expect HTML... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + /* + * See if we need to show a list of jobs or the status of a + * single job... + */ + + job = argv[0]; + if (strcmp(job, "/") == 0 || strcmp(job, "jobs.cgi") == 0) + job = NULL; + + /* + * Print the standard header... + */ + + puts(""); + puts(""); + if (job) + puts(""); + else + puts(""); + printf("%s on %s - Common UNIX Printing System\n", + job == NULL ? "Jobs" : job, getenv("SERVER_NAME")); + puts(""); + puts(""); + puts("\"Current"); + puts("\"Current"); + puts("\"Current"); + puts("\"Read"); +#ifdef ESPPRINTPRO + puts("\"Download"); + puts("\"Get"); +#else + puts("\"Download"); +#endif /* ESPPRINTPRO */ + puts(""); + puts(""); + puts(""); + puts("

"); + puts(""); + puts("\"Easy"); +#ifdef ESPPRINTPRO + puts(""); +#else + puts(""); +#endif /* ESPPRINTPRO */ + + fflush(stdout); + + /* + * Show the information... + */ + + if (job == NULL) + show_job_list(http, language); + else + show_job_info(http, language, job); + + /* + * Write a standard trailer... + */ + + puts("


"); + + puts("

The Common UNIX Printing System, CUPS, and the CUPS logo are the"); + puts("trademark property of Easy Software"); + puts("Products. CUPS is copyright 1997-1999 by Easy Software Products,"); + puts("All Rights Reserved."); + + puts(""); + puts(""); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'show_job_list()' - Show a list of jobs... + */ + +static void +show_job_list(http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + char *job_uri, /* job-uri */ + *printer_uri, /* job-printer-uri */ + *job_name, /* job-name */ + *job_user; /* job-originating-user-name */ + int job_id, /* job-id */ + job_priority, /* job-priority */ + job_k_octets, /* job-k-octets */ + copies; /* copies */ + ipp_jstate_t job_state; /* job-state */ + + + printf("

Jobs on %s

\n", getenv("SERVER_NAME")); + + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + 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, "job-uri", + NULL, "ipp://localhost/jobs/"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/jobs/")) != NULL) + { + /* + * Do a table for the jobs... + */ + + puts("
"); + puts(""); + puts(""); + printf("\n", cupsLangString(language, CUPS_MSG_PRINT_JOBS)); + printf("\n", cupsLangString(language, CUPS_MSG_JOB_STATE)); + printf("\n", cupsLangString(language, CUPS_MSG_JOB_NAME)); + printf("\n", cupsLangString(language, CUPS_MSG_USER_NAME)); + printf("\n", cupsLangString(language, CUPS_MSG_PRIORITY)); + printf("\n", cupsLangString(language, CUPS_MSG_COPIES)); + printf("\n", cupsLangString(language, CUPS_MSG_FILE_SIZE)); + puts(""); + + /* + * Loop through the jobs returned in the list and display + * their devices... + */ + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Show the job status for each job... + */ + + job_uri = NULL; + printer_uri = NULL; + job_name = "unknown"; + job_user = "unknown"; + job_id = 0; + job_priority = 50; + job_k_octets = 0; + copies = 1; + job_state = IPP_JOB_PENDING; + + while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + { + if (strcmp(attr->name, "job-uri") == 0 && + attr->value_tag == IPP_TAG_URI) + job_uri = attr->values[0].string.text; + + if (strcmp(attr->name, "job-printer-uri") == 0 && + attr->value_tag == IPP_TAG_URI) + printer_uri = attr->values[0].string.text; + + if (strcmp(attr->name, "job-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + job_name = attr->values[0].string.text; + + if (strcmp(attr->name, "job-originating-user-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + job_user = attr->values[0].string.text; + + if (strcmp(attr->name, "job-id") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + job_id = attr->values[0].integer; + + if (strcmp(attr->name, "job-priority") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + job_priority = attr->values[0].integer; + + if (strcmp(attr->name, "job-k-octets") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + job_k_octets = attr->values[0].integer; + + if (strcmp(attr->name, "copies") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + copies = attr->values[0].integer; + + if (strcmp(attr->name, "job-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + job_state = (ipp_jstate_t)attr->values[0].integer; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (job_id && job_uri != NULL && printer_uri != NULL) + { + puts(""); + printf("\n", + getenv("SERVER_NAME"), getenv("SERVER_PORT"), job_id, + strrchr(printer_uri, '/') + 1, job_id); + printf("\n", job_state == IPP_JOB_PROCESSING ? + cupsLangString(language, CUPS_MSG_PROCESSING) : + cupsLangString(language, CUPS_MSG_PENDING)); + printf("\n", job_name); + printf("\n", job_user); + printf("\n", job_priority); + printf("\n", copies); + printf("\n", job_k_octets); + puts(""); + } + + if (attr == NULL) + break; + } + + ippDelete(response); + + puts("
%s%s%s%s%s%s%s
%s-%d%s%s%s%d%d%dk
"); + puts("
"); + } + else + puts("

No jobs found."); +} + + +/* + * 'show_job_info()' - Show job information. + */ + +static void +show_job_info(http_t *http, /* I - Server connection */ + cups_lang_t *language, /* I - Language */ + char *name) /* I - Job "name" */ +{ + int i; /* Looping var */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + char uri[HTTP_MAX_URI];/* Real URI */ + char *job_uri, /* job-uri */ + *printer_uri, /* job-printer-uri */ + *job_name, /* job-name */ + *job_user; /* job-originating-user-name */ + int job_id, /* job-id */ + job_priority, /* job-priority */ + job_k_octets; /* job-k-octets */ + ipp_jstate_t job_state; /* job-state */ + + + /* + * Build an IPP_GET_JOB_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOB_ATTRIBUTES; + request->request.op.request_id = 1; + + 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); + + sprintf(uri, "ipp://localhost/jobs/%s", name); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, uri + 15)) == NULL) + { + puts("

Unable to communicate with CUPS server!"); + return; + } + + if (response->request.status.status_code == IPP_NOT_FOUND) + { + puts("

Job does not exist or has completed."); + ippDelete(response); + return; + } + + /* + * Get the job status for this job... + */ + + if ((attr = ippFindAttribute(response, "job-uri", IPP_TAG_URI)) != NULL) + job_uri = attr->values[0].string.text; + else + { + puts("

Missing job-uri attribute!"); + ippDelete(request); + return; + } + + if ((attr = ippFindAttribute(response, "job-printer-uri", IPP_TAG_URI)) != NULL) + printer_uri = attr->values[0].string.text; + else + { + puts("

Missing job-printer-uri attribute!"); + ippDelete(request); + return; + } + + if ((attr = ippFindAttribute(response, "job-name", IPP_TAG_NAME)) != NULL) + job_name = attr->values[0].string.text; + else + job_name = "unknown"; + + if ((attr = ippFindAttribute(response, "job-originating-user-name", + IPP_TAG_NAME)) != NULL) + job_user = attr->values[0].string.text; + else + job_user = "unknown"; + + if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) != NULL) + job_id = attr->values[0].integer; + else + { + puts("

Missing job-id attribute!"); + ippDelete(request); + return; + } + + if ((attr = ippFindAttribute(response, "job-priority", IPP_TAG_INTEGER)) != NULL) + job_priority = attr->values[0].integer; + else + job_priority = 50; + + if ((attr = ippFindAttribute(response, "job-k-octets", IPP_TAG_INTEGER)) != NULL) + job_k_octets = attr->values[0].integer; + else + job_k_octets = 0; + + if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL) + job_state = (ipp_jstate_t)attr->values[0].integer; + else + job_state = IPP_JOB_PENDING; + + /* + * Do a table for the job... + */ + + printf("

%s-%d

\n", + getenv("SERVER_NAME"), getenv("SERVER_PORT"), + strrchr(printer_uri, '/') + 1, strrchr(printer_uri, '/') + 1, job_id); + + puts("
"); + puts(""); + + puts(""); + printf("\n", cupsLangString(language, CUPS_MSG_JOB_STATE)); + printf("\n", job_state == IPP_JOB_PROCESSING ? + cupsLangString(language, CUPS_MSG_PROCESSING) : + cupsLangString(language, CUPS_MSG_PENDING)); + puts(""); + + puts(""); + printf("\n", cupsLangString(language, CUPS_MSG_JOB_NAME)); + printf("\n", job_name); + puts(""); + + puts(""); + printf("\n", cupsLangString(language, CUPS_MSG_USER_NAME)); + printf("\n", job_user); + puts(""); + + puts(""); + printf("\n", cupsLangString(language, CUPS_MSG_PRIORITY)); + printf("\n", job_priority); + puts(""); + + puts(""); + printf("\n", cupsLangString(language, CUPS_MSG_FILE_SIZE)); + printf("\n", job_k_octets); + puts(""); + + puts(""); + printf("\n", cupsLangString(language, CUPS_MSG_OPTIONS)); + puts(""); + puts(""); + puts("
%s%s
%s%s
%s%s
%s%d
%s%dk
%s"); + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + if (attr->group_tag != IPP_TAG_JOB && + attr->group_tag != IPP_TAG_EXTENSION) + continue; + + if (strcmp(attr->name, "job-uri") == 0 || + strcmp(attr->name, "job-printer-uri") == 0 || + strcmp(attr->name, "job-name") == 0 || + strcmp(attr->name, "job-originating-user-name") == 0 || + strcmp(attr->name, "job-id") == 0 || + strcmp(attr->name, "job-priority") == 0 || + strcmp(attr->name, "job-k-octets") == 0 || + strcmp(attr->name, "job-state") == 0) + continue; + + if (attr->value_tag != IPP_TAG_BOOLEAN) + printf("%s=", attr->name); + + for (i = 0; i < attr->num_values; i ++) + { + if (i) + putchar(','); + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + printf("%d", attr->values[i].integer); + break; + + case IPP_TAG_BOOLEAN : + if (!attr->values[i].boolean) + printf("no"); + + case IPP_TAG_NOVALUE : + fputs(attr->name, stdout); + break; + + case IPP_TAG_RANGE : + printf("%d-%d", attr->values[i].range.lower, + attr->values[i].range.upper); + break; + + case IPP_TAG_RESOLUTION : + printf("%dx%d%s", attr->values[i].resolution.xres, + attr->values[i].resolution.yres, + attr->values[i].resolution.units == IPP_RES_PER_INCH ? + "dpi" : "dpc"); + break; + + case IPP_TAG_STRING : + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + case IPP_TAG_URI : + printf("\"%s\"", attr->values[i].string.text); + break; + } + } + + puts("
"); + } + + puts("
"); + + ippDelete(response); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/printers.c b/cgi-bin/printers.c new file mode 100644 index 0000000000..7756161ed5 --- /dev/null +++ b/cgi-bin/printers.c @@ -0,0 +1,486 @@ +/* + * "$Id$" + * + * Printer status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + * show_printer_list() - Show a list of printers... + * show_printer_info() - Show printer information. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static void show_printer_list(http_t *http, cups_lang_t *language); +static void show_printer_info(http_t *http, cups_lang_t *language, + char *name); + + +/* + * 'main()' - Main entry for CGI. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Language information */ + char *printer; /* Printer name */ + http_t *http; /* Connection to the server */ + + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Tell the client to expect HTML... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + /* + * See if we need to show a list of printers or the status of a + * single printer... + */ + + printer = argv[0]; + if (strcmp(printer, "/") == 0 || strcmp(printer, "printers.cgi") == 0) + printer = NULL; + + /* + * Print the standard header... + */ + + puts(""); + puts(""); + if (printer) + puts(""); + else + puts(""); + printf("%s on %s - Common UNIX Printing System\n", + printer == NULL ? "Printers" : printer, getenv("SERVER_NAME")); + puts(""); + puts(""); + puts("\"Current"); + puts("\"Current"); + puts("\"Current"); + puts("\"Read"); +#ifdef ESPPRINTPRO + puts("\"Download"); + puts("\"Get"); +#else + puts("\"Download"); +#endif /* ESPPRINTPRO */ + puts(""); + puts(""); + puts(""); + puts("

"); + puts(""); + puts("\"Easy"); +#ifdef ESPPRINTPRO + puts(""); +#else + puts(""); +#endif /* ESPPRINTPRO */ + + printf("

%s on %s

\n", printer == NULL ? "Printers" : printer, + getenv("SERVER_NAME")); + fflush(stdout); + + puts("
"); + puts(""); + puts(""); + puts(""); + puts(""); + puts(""); + puts(""); + + /* + * Show the information... + */ + + if (printer == NULL) + show_printer_list(http, language); + else + show_printer_info(http, language, printer); + + /* + * Write a standard trailer... + */ + + puts("
NameStatusJobs
"); + puts("
"); + + puts("
"); + + puts("

The Common UNIX Printing System, CUPS, and the CUPS logo are the"); + puts("trademark property of Easy Software"); + puts("Products. CUPS is copyright 1997-1999 by Easy Software Products,"); + puts("All Rights Reserved."); + + puts(""); + puts(""); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'show_printer_list()' - Show a list of printers... + */ + +static void +show_printer_list(http_t *http, /* I - HTTP connection */ + cups_lang_t *language)/* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + + + /* + * Build a CUPS_GET_PRINTERS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PRINTERS; + request->request.op.request_id = 1; + + + 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); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/printers/")) != NULL) + { + /* + * Loop through the printers returned in the list and display + * their devices... + */ + + for (attr = response->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Show the printer status for each printer... + */ + + while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) + { + if (strcmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + show_printer_info(http, language, attr->values[0].string.text); + + attr = attr->next; + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } +} + + +/* + * 'show_printer_info()' - Show printer information. + */ + +static void +show_printer_info(http_t *http, + cups_lang_t *language, + char *name) +{ + ipp_t *request, /* IPP request */ + *response, /* IPP response */ + *jobs; /* IPP Get Jobs response */ + int jobcount; /* Number of jobs */ + ipp_attribute_t *attr; /* IPP attribute */ + char *message; /* Printer state message */ + int accepting; /* Accepting requests? */ + ipp_pstate_t pstate; /* Printer state */ + char uri[HTTP_MAX_URI];/* Printer URI */ + + + /* + * Build a IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + 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); + + sprintf(uri, "ipp://localhost/printers/%s", name); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, uri + 15)) == NULL) + { + puts("

Unable to communicate with CUPS server!"); + return; + } + + if (response->request.status.status_code == IPP_NOT_FOUND) + { + puts("

Printer does not exist."); + ippDelete(response); + return; + } + + /* + * Grab the needed printer attributes... + */ + + if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) + pstate = (ipp_pstate_t)attr->values[0].integer; + else + pstate = IPP_PRINTER_IDLE; + + if ((attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT)) != NULL) + message = attr->values[0].string.text; + else + message = NULL; + + if ((attr = ippFindAttribute(response, "printer-is-accepting-jobs", + IPP_TAG_BOOLEAN)) != NULL) + accepting = attr->values[0].boolean; + else + accepting = 1; + + if ((attr = ippFindAttribute(response, "printer-uri-supported", IPP_TAG_URI)) != NULL) + { + strcpy(uri, "http:"); + strcpy(uri + 5, strchr(attr->values[0].string.text, '/')); + } + + /* + * Display the printer entry... + */ + + puts(""); + + printf("%s\n", uri, name); + + printf("\n", + pstate == IPP_PRINTER_IDLE ? "idle" : + pstate == IPP_PRINTER_PROCESSING ? "processing" : "stopped"); + + printf("%s: %s, %s
\n", + cupsLangString(language, CUPS_MSG_PRINTER_STATE), + cupsLangString(language, pstate == IPP_PRINTER_IDLE ? CUPS_MSG_IDLE : + pstate == IPP_PRINTER_PROCESSING ? + CUPS_MSG_PROCESSING : CUPS_MSG_STOPPED), + cupsLangString(language, accepting ? CUPS_MSG_ACCEPTING_JOBS : + CUPS_MSG_NOT_ACCEPTING_JOBS)); + + if (message) + printf("
\"%s\"\n", message); + else if (!accepting || pstate == IPP_PRINTER_STOPPED) + puts("
\"Reason Unknown\""); + + puts(""); + + /* + * Show a list of jobs as needed... + */ + + if (pstate != IPP_PRINTER_IDLE) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + 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); + + sprintf(uri, "ipp://localhost/printers/%s", name); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + jobs = cupsDoRequest(http, request, uri + 15); + } + else + jobs = NULL; + + puts(""); + jobcount = 0; + + if (jobs != NULL) + { + char *username; /* Pointer to job-originating-user-name */ + int jobid, /* job-id */ + size; /* job-k-octets */ + + + for (attr = jobs->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip leading attributes until we hit a job... + */ + + while (attr != NULL && attr->group_tag != IPP_TAG_JOB) + attr = attr->next; + + if (attr == NULL) + break; + + /* + * Pull the needed attributes from this job... + */ + + jobid = 0; + size = 0; + username = NULL; + + while (attr != NULL && attr->group_tag == IPP_TAG_JOB) + { + if (strcmp(attr->name, "job-id") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobid = attr->values[0].integer; + + if (strcmp(attr->name, "job-k-octets") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + size = attr->values[0].integer; + + if (strcmp(attr->name, "job-originating-user-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + username = attr->values[0].string.text; + + attr = attr->next; + } + + /* + * Display the job if it matches the current printer... + */ + + if (username != NULL) + { + jobcount ++; + printf("%s-%d %s %dk
\n", jobid, name, + jobid, username, size); + } + + if (attr == NULL) + break; + } + + ippDelete(jobs); + } + + if (jobcount == 0) + puts("None"); + puts(""); + puts(""); + + ippDelete(response); +} + + +/* + * End of "$Id$". + */ diff --git a/conf/Makefile b/conf/Makefile new file mode 100644 index 0000000000..2859b7064d --- /dev/null +++ b/conf/Makefile @@ -0,0 +1,68 @@ +# +# "$Id$" +# +# Configuration file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Config files... +# + +KEEP = classes.conf cupsd.conf printers.conf +REPLACE = mime.convs mime.types + +# +# Make everything... +# + +all: + +# +# Clean all config and object files... +# + +clean: + +# +# Install files... +# + +install: + -$(MKDIR) $(SERVERROOT)/conf + for file in $(KEEP); do \ + if test -e $(SERVERROOT)/conf/$$file ; then \ + $(CP) $$file $(SERVERROOT)/conf/$$file.N ; \ + else \ + $(CP) $$file $(SERVERROOT)/conf ; \ + fi ; \ + done + for file in $(REPLACE); do \ + if test -e $(SERVERROOT)/conf/$$file ; then \ + $(MV) $(SERVERROOT)/conf/$$file $(SERVERROOT)/conf/$$file.O ; \ + fi ; \ + $(CP) $$file $(SERVERROOT)/conf ; \ + done + +# +# End of "$Id$". +# diff --git a/conf/classes.conf b/conf/classes.conf new file mode 100644 index 0000000000..cb6a341e80 --- /dev/null +++ b/conf/classes.conf @@ -0,0 +1,72 @@ +# +# "$Id: classes.conf 333 1999-05-17 18:03:40Z mike $" +# +# Sample class configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44145 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is a sample class configuration file. This file is included # +# from the main configuration file (cups.conf) and lists all of the # +# printer classes known to the system. # +# # +######################################################################## + +# +# Each class starts with a definition. Class names +# can be up to 128 characters in length and are *not* case sensitive. +# +# One entry can appear in this file; if you don't +# define a default destination, the first printer or class becomes +# the default. +# + +# +# +# Info: the description for the class. +# + +#Info Acme LaserPrint 1000 Printers + +# +# MoreInfo: a URL for more information on the printer. +# + +#MoreInfo http://www.acme.com/lp1000.html + +# +# Location: the location of the printer. +# + +#Location Room 101 in the activities building + +# +# Printer: adds a printer to the class. +# + +#Printer sample +#Printer sample@host2 +# + +# +# End of "$Id: classes.conf 333 1999-05-17 18:03:40Z mike $". +# diff --git a/conf/cupsd.conf b/conf/cupsd.conf new file mode 100644 index 0000000000..cb54f7ff19 --- /dev/null +++ b/conf/cupsd.conf @@ -0,0 +1,369 @@ +# +# "$Id: cupsd.conf 628 1999-08-23 15:24:48Z mike $" +# +# Sample configuration file for the Common UNIX Printing System (CUPS) +# scheduler. +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44145 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is the CUPS configuration file. If you are familiar with # +# Apache or any of the other popular web servers, we've followed the # +# same format. Any configuration variable used here has the same # +# semantics as the corresponding variable in Apache. If we need # +# different functionality then a different name is used to avoid # +# confusion... # +# # +######################################################################## + +# +# Ports/addresses that we listen to. The default port 631 is reserved +# for the Internet Printing Protocol (IPP) and is what we use here. +# +# You can have multiple Port/Listen lines to listen to more than one +# port or address, or to restrict access: +# +# Port 80 +# Port 631 +# Listen hostname +# Listen hostname:80 +# Listen hostname:631 +# Listen 1.2.3.4 +# Listen 1.2.3.4:631 +# + +#Port 80 +Port 631 + +# +# MaxClients: controls the maximum number of simultaneous clients that +# will be handled. Defaults to 100. +# + +#MaxClients 100 + +# +# User/Group: the user and group the server runs under. Normally this +# must be lp and sys, however you can configure things for another user +# or group as needed. +# +# Note: the server must be run initially as root to support the +# default IPP port of 631. It changes users whenever an external +# program is run... +# + +#User lp +#Group sys + +# +# SystemGroup: the group name for "System" (printer administration) +# access. The default varies depending on the operating system, but +# will be "sys", "system", or "root" (checked for in that order.) +# + +#SystemGroup sys + +# +# ServerName: the hostname of your server, as advertised to the world. +# By default CUPS will use the hostname of the system. +# +# This is also the name used by clients when connecting to the local +# server, so you can use this to configure a client machine without +# a local server running. +# + +#ServerName myhost.domain.com + +# +# ServerAdmin: the email address to send all complaints/problems to. +# By default CUPS will use "root@hostname". +# + +#ServerAdmin root@your.domain.com + +# +# ServerRoot: the root directory for the scheduler. +# By default the compiled-in value. +# + +#ServerRoot /var/cups + +# +# AccessLog: the access log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/access_log" +# + +#AccessLog logs/access_log + +# +# ErrorLog: the error log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/error_log" +# + +#ErrorLog logs/error_log + +# +# PageLog: the page log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/page_log" +# + +#PageLog logs/page_log + +# +# LogLevel: controls the number of messages logged to the ErrorLog +# file and can be one of the following: +# +# debug Log everything. +# info Log all requests and state changes. +# warn Log errors and warnings. +# error Log only errors. +# none Log nothing. +# + +LogLevel info + +# +# MaxLogSize: controls the maximum size of each log file before they are +# rotated. Defaults to 1048576 (1MB). Set to 0 to disable log rotating. +# + +#MaxLogSize 0 + +# +# MaxRequestSize: controls the maximum size of print files. Set to 0 to +# disable this feature (defaults to 0.) +# + +#MaxRequestSize 0 + +# +# HostNameLookups: whether or not to do lookups on IP addresses to get a +# fully-qualified hostname. This defaults to Off for performance reasons... +# + +#HostNameLookups On + +# +# Timeout: the timeout before requests time out. Default is 300 seconds. +# + +#Timeout 300 + +# +# KeepAlive: whether or not to support the Keep-Alive connection +# option. Default is on. +# + +#KeepAlive On + +# +# KeepAliveTimeout: the timeout before Keep-Alive connections are +# automatically closed. Default is 60 seconds. +# + +#KeepAliveTimeout 60 + +# +# ImplicitClasses: whether or not to use implicit classes. +# +# Printer classes can be specified explicitly in the classes.conf +# file, implicitly based upon the printers available on the LAN, or +# both. +# +# When ImplicitClasses is On, printers on the LAN with the same name +# (e.g. Acme-LaserPrint-1000) will be put into a class with the same +# name. This allows you to setup multiple redundant queues on a LAN +# without a lot of administrative difficulties. If a user sends a +# job to Acme-LaserPrint-1000, the job will go to the first available +# queue. +# +# Enabled by default. +# + +#ImplicitClasses On + +# +# Browsing: whether or not to broadcast printer information to +# other CUPS servers. Enabled by default. +# + +#Browsing On + +# +# BrowseInterval: the time between browsing updates in seconds. Default +# is 30 seconds. +# +# Note that browsing information is sent whenever a printer's state changes +# as well, so this represents the maximum time between updates. +# + +#BrowseInterval 30 + +# +# BrowseTimeout: the timeout for network printers - if we don't +# get an update within this time the printer will be removed +# from the printer list. This number definitely should not be +# less the BrowseInterval value for obvious reasons. Defaults +# to 300 seconds. +# + +#BrowseTimeout 300 + +# +# BrowsePort: the port used for UDP broadcasts. By default this is +# the IPP port; if you change this you need to do it on all servers. +# Only one BrowsePort is recognized. +# + +#BrowsePort 631 + +# +# BrowseAddress: specifies a broadcast address to be used. By +# default browsing information is broadcast to all active interfaces. +# +# Note: HP-UX 10.20 and earlier do not properly handle broadcast unless +# you have a Class A, B, C, or D netmask (i.e. no CIDR support). +# + +#BrowseAddress x.y.z.255 +#BrowseAddress x.y.255.255 +#BrowseAddress x.255.255.255 + +# +# DocumentRoot: the root directory for HTTP documents that are served. +# By default the compiled in directory. +# + +#DocumentRoot /usr/share/cups/doc + +# +# DefaultLanguage: the default language if not specified by the browser. +# If not specified, the current locale is used. +# + +#DefaultLanguage en + +# +# DefaultCharset: the default character set to use. If not specified, +# defaults to iso-8859-1. Note that this can also be overridden in +# HTML documents... +# + +#DefaultCharset iso-8859-1 + +# +# RIPCache: the amount of memory that each RIP should use to cache +# bitmaps. The value can be any real number followed by "k" for +# kilobytes, "m" for megabytes, "g" for gigabytes, or "t" for tiles +# (1 tile = 256x256 pixels.) Defaults to "8m" (8 megabytes). +# + +#RIPCache 8m + +# +# TempDir: the directory to put temporary files in. This directory must be +# writable by the user defined above! Defaults to "/var/tmp" or the value +# of the TMPDIR environment variable. +# + +#TempDir /var/tmp + +# +# Access permissions for each directory served by the scheduler. +# Locations are relative to DocumentRoot... +# +# AuthType: the authorization to use; currently only "Basic" authorization is +# supported. +# +# AuthClass: the authorization class; currently only "Anonymous", "User", +# "System" (valid user belonging to group SystemGroup), and "Group" +# (valid user belonging to the specified group) are supported. +# +# AuthGroupName: the group name for "Group" authorization. +# +# Order: the order of Allow/Deny processing. +# +# Allow: allows access from the specified hostname, domain, IP address, or +# network. +# +# Deny: denies access from the specified hostname, domain, IP address, or +# network. +# +# Both "Allow" and "Deny" accept the following notations for addresses: +# +# All +# None +# *.domain.com +# .domain.com +# host.domain.com +# nnn.* +# nnn.nnn.* +# nnn.nnn.nnn.* +# nnn.nnn.nnn.nnn +# nnn.nnn.nnn.nnn/mm +# nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm +# +# The host and domain address require that you enable hostname lookups +# with "HostNameLookups On" above. +# + + + + + +# +# You may wish to limit access to printers and classes, either with Allow +# and Deny lines, or by requiring a username and password. +# + +## Require a username and password +#AuthType Basic +#AuthClass User + +## Restrict access to local domain +#Order Deny,Allow +#Deny From All +#Allow From .mydomain.com + + + +# +# You definitely will want to limit access to the administration tools. +# The default configuration requires a local connection from a user who +# is a member of the system group to do any admin tasks. You can change +# the group name using the SystemGroup directive. +# + +AuthType Basic +AuthClass System + +## Restrict access to local domain +Order Deny,Allow +Deny From All +Allow From 127.0.0.1 + + +# +# End of "$Id: cupsd.conf 628 1999-08-23 15:24:48Z mike $". +# diff --git a/conf/cupsd.conf-personal b/conf/cupsd.conf-personal new file mode 100644 index 0000000000..b82b66d976 --- /dev/null +++ b/conf/cupsd.conf-personal @@ -0,0 +1,250 @@ +# +# "$Id: cupsd.conf-personal 407 1999-06-17 20:02:43Z mike $" +# +# Scheduler configuration file for ESP Print Personal. +# + +######################################################################## +# # +# This is the CUPS configuration file. If you are familiar with # +# Apache or any of the other popular web servers, we've followed the # +# same format. Any configuration variable used here has the same # +# semantics as the corresponding variable in Apache. If we need # +# different functionality then a different name is used to avoid # +# confusion... # +# # +######################################################################## + +# +# Ports/addresses that we listen to. The default port 631 is reserved +# for the Internet Printing Protocol (IPP) and is what we use here. +# +# You can have multiple Listen lines to listen to more than one +# port: +# +# Listen 127.0.0.1:80 +# Listen 127.0.0.1:631 +# +# For ESP Print Personal, we can only listen on the local host... +# + +#Listen 127.0.0.1:80 +Listen 127.0.0.1:631 + +# +# User/Group: the user and group the server runs under. Normally this +# must be lp and sys, however you can configure things for another user +# or group as needed. +# +# Note: the server must be run initially as root to support the +# default IPP port of 631. It changes users whenever an external +# program is run... +# + +User lp +Group sys + +# +# SystemGroup: the group name for "System" (printer administration) +# access. +# + +SystemGroup sys + +# +# ServerName: the hostname of your server, as advertised to the world. +# By default CUPS will use the hostname of the system. +# + +#ServerName myhost.domain.com + +# +# ServerAdmin: the email address to send all complaints/problems to. +# By default CUPS will use "root@hostname". +# + +#ServerAdmin root@your.domain.com + +# +# ServerRoot: the root directory for the scheduler. +# By default the compiled-in value. +# + +#ServerRoot /var/cups + +# +# AccessLog: the access log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/access_log" +# + +#AccessLog logs/access_log + +# +# ErrorLog: the error log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/error_log" +# + +#ErrorLog logs/error_log + +# +# PageLog: the page log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/page_log" +# + +#PageLog logs/page_log + +# +# LogLevel: controls the number of messages logged to the ErrorLog +# file and can be one of the following: +# +# debug Log everything. +# info Log all requests and state changes. +# warn Log errors and warnings. +# error Log only errors. +# none Log nothing. +# + +LogLevel info + +# +# MaxLogSize: controls the maximum size of each log file before they are +# rotated. Defaults to 1048576 (1MB). Set to 0 to disable log rotating. +# + +#MaxLogSize 0 + +# +# MaxRequestSize: controls the maximum size of print files. Set to 0 to +# disable this feature (defaults to 0.) +# + +#MaxRequestSize 0 + +# +# HostNameLookups: whether or not to do lookups on IP addresses to get a +# fully-qualified hostname. This defaults to Off for performance reasons... +# + +#HostNameLookups On + +# +# Timeout: the timeout before requests time out. Default is 300 seconds. +# + +#Timeout 300 + +# +# KeepAlive: whether or not to support the Keep-Alive connection +# option. Default is on. +# + +#KeepAlive On + +# +# KeepAliveTimeout: the timeout before Keep-Alive connections are +# automatically closed. Default is 60 seconds. +# + +#KeepAliveTimeout 60 + +# +# Browsing: not available in ESP Print Personal. +# + +Browsing Off + +# +# DocumentRoot: the root directory for HTTP documents that are served. +# By default the compiled in directory. +# + +#DocumentRoot /usr/share/cups/doc + +# +# DefaultLanguage: the default language if not specified by the browser. +# If not specified, the current locale is used. +# + +#DefaultLanguage en + +# +# DefaultCharset: the default character set to use. If not specified, +# defaults to iso-8859-1. Note that this can also be overridden in +# HTML documents... +# + +#DefaultCharset iso-8859-1 + +# +# RIPCache: the amount of memory that each RIP should use to cache +# bitmaps. The value can be any real number followed by "k" for +# kilobytes, "m" for megabytes, "g" for gigabytes, or "t" for tiles +# (1 tile = 256x256 pixels.) Defaults to "32m" (32 megabytes). +# + +#RIPCache: 32m + +# +# Access permissions for each directory served by the scheduler. +# Locations are relative to DocumentRoot... +# +# AuthType: the authorization to use; currently only "Basic" authorization is +# supported. +# +# AuthClass: the authorization class; currently only "Anonymous", "User", +# "System" (valid user belonging to group SystemGroup), and "Group" +# (valid user belonging to the specified group) are supported. +# +# AuthGroupName: the group name for "Group" authorization. +# +# Order: the order of Allow/Deny processing. +# +# Allow: allows access from the specified hostname, domain, IP address, or +# network. +# +# Deny: denies access from the specified hostname, domain, IP address, or +# network. +# + + + + + +# +# You may wish to limit access to printers and classes, either with Allow +# and Deny lines, or by requiring a username and password. +# + +## Require a username and password +#AuthType Basic +#AuthClass User + +## Restrict access to local domain +#Order Deny,Allow +#Deny From All +#Allow From .mydomain.com + + + +# +# You definitely will want to limit access to the administration tools. +# The default configuration requires a local connection from a user who +# is a member of group "sys" to do any admin tasks. You can change the +# group name using the SystemGroup directive. +# + +AuthType Basic +AuthClass System + +## Restrict access to local domain +Order Deny,Allow +Deny From All +Allow From 127.0.0.1 + + +# +# End of "$Id: cupsd.conf-personal 407 1999-06-17 20:02:43Z mike $". +# diff --git a/conf/cupsd.conf-professional b/conf/cupsd.conf-professional new file mode 100644 index 0000000000..c7bd3324bf --- /dev/null +++ b/conf/cupsd.conf-professional @@ -0,0 +1,313 @@ +# +# "$Id: cupsd.conf-professional 407 1999-06-17 20:02:43Z mike $" +# +# Scheduler configuration file for ESP Print Professional. +# + +######################################################################## +# # +# This is the CUPS configuration file. If you are familiar with # +# Apache or any of the other popular web servers, we've followed the # +# same format. Any configuration variable used here has the same # +# semantics as the corresponding variable in Apache. If we need # +# different functionality then a different name is used to avoid # +# confusion... # +# # +######################################################################## + +# +# Ports/addresses that we listen to. The default port 631 is reserved +# for the Internet Printing Protocol (IPP) and is what we use here. +# +# You can have multiple Port/Listen lines to listen to more than one +# port or address, or to restrict access: +# +# Port 80 +# Port 631 +# Listen hostname +# Listen hostname:80 +# Listen hostname:631 +# Listen 1.2.3.4 +# Listen 1.2.3.4:631 +# + +#Port 80 +Port 631 + +# +# User/Group: the user and group the server runs under. Normally this +# must be lp and sys, however you can configure things for another user +# or group as needed. +# +# Note: the server must be run initially as root to support the +# default IPP port of 631. It changes users whenever an external +# program is run... +# + +User lp +Group sys + +# +# SystemGroup: the group name for "System" (printer administration) +# access. +# + +SystemGroup sys + +# +# ServerName: the hostname of your server, as advertised to the world. +# By default CUPS will use the hostname of the system. +# + +#ServerName myhost.domain.com + +# +# ServerAdmin: the email address to send all complaints/problems to. +# By default CUPS will use "root@hostname". +# + +#ServerAdmin root@your.domain.com + +# +# ServerRoot: the root directory for the scheduler. +# By default the compiled-in value. +# + +#ServerRoot /var/cups + +# +# AccessLog: the access log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/access_log" +# + +#AccessLog logs/access_log + +# +# ErrorLog: the error log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/error_log" +# + +#ErrorLog logs/error_log + +# +# PageLog: the page log file; if this does not start with a leading / +# then it is assumed to be relative to ServerRoot. By default set to +# "logs/page_log" +# + +#PageLog logs/page_log + +# +# LogLevel: controls the number of messages logged to the ErrorLog +# file and can be one of the following: +# +# debug Log everything. +# info Log all requests and state changes. +# warn Log errors and warnings. +# error Log only errors. +# none Log nothing. +# + +LogLevel info + +# +# MaxLogSize: controls the maximum size of each log file before they are +# rotated. Defaults to 1048576 (1MB). Set to 0 to disable log rotating. +# + +#MaxLogSize 0 + +# +# MaxRequestSize: controls the maximum size of print files. Set to 0 to +# disable this feature (defaults to 0.) +# + +#MaxRequestSize 0 + +# +# HostNameLookups: whether or not to do lookups on IP addresses to get a +# fully-qualified hostname. This defaults to Off for performance reasons... +# + +#HostNameLookups On + +# +# Timeout: the timeout before requests time out. Default is 300 seconds. +# + +#Timeout 300 + +# +# KeepAlive: whether or not to support the Keep-Alive connection +# option. Default is on. +# + +#KeepAlive On + +# +# KeepAliveTimeout: the timeout before Keep-Alive connections are +# automatically closed. Default is 60 seconds. +# + +#KeepAliveTimeout 60 + +# +# ImplicitClasses: whether or not to use implicit classes. +# +# Printer classes can be specified explicitly in the classes.conf +# file, implicitly based upon the printers available on the LAN, or +# both. +# +# When ImplicitClasses is On, printers on the LAN with the same name +# (e.g. Acme-LaserPrint-1000) will be put into a class with the same +# name. This allows you to setup multiple redundant queues on a LAN +# without a lot of administrative difficulties. If a user sends a +# job to Acme-LaserPrint-1000, the job will go to the first available +# queue. +# +# Enabled by default. +# + +#ImplicitClasses On + +# +# Browsing: whether or not to broadcast printer information to +# other CUPS servers. Enabled by default. +# + +#Browsing On + +# +# BrowseInterval: the time between browsing updates in seconds. Default +# is 30 seconds. +# +# Note that browsing information is sent whenever a printer's state changes +# as well, so this represents the maximum time between updates. +# + +#BrowseInterval 30 + +# +# BrowseTimeout: the timeout for network printers - if we don't +# get an update within this time the printer will be removed +# from the printer list. This number definitely should not be +# less the BrowseInterval value for obvious reasons. Defaults +# to 300 seconds. +# + +#BrowseTimeout 300 + +# +# BrowsePort: the port used for UDP broadcasts. By default this is +# the IPP port; if you change this you need to do it on all servers. +# Only one BrowsePort is recognized. +# + +#BrowsePort 631 + +# +# BrowseAddress: specifies a broadcast address to be used. By +# default browsing information is broadcast to all active interfaces. +# +# Note: HP-UX 10.20 and earlier do not properly handle broadcast unless +# you have a Class A, B, C, or D netmask (i.e. no CIDR support). +# + +#BrowseAddress x.y.z.255 +#BrowseAddress x.y.255.255 +#BrowseAddress x.255.255.255 + +# +# DocumentRoot: the root directory for HTTP documents that are served. +# By default the compiled in directory. +# + +#DocumentRoot /usr/share/cups/doc + +# +# DefaultLanguage: the default language if not specified by the browser. +# If not specified, the current locale is used. +# + +#DefaultLanguage en + +# +# DefaultCharset: the default character set to use. If not specified, +# defaults to iso-8859-1. Note that this can also be overridden in +# HTML documents... +# + +#DefaultCharset iso-8859-1 + +# +# RIPCache: the amount of memory that each RIP should use to cache +# bitmaps. The value can be any real number followed by "k" for +# kilobytes, "m" for megabytes, "g" for gigabytes, or "t" for tiles +# (1 tile = 256x256 pixels.) Defaults to "32m" (32 megabytes). +# + +#RIPCache: 32m + +# +# Access permissions for each directory served by the scheduler. +# Locations are relative to DocumentRoot... +# +# AuthType: the authorization to use; currently only "Basic" authorization is +# supported. +# +# AuthClass: the authorization class; currently only "Anonymous", "User", +# "System" (valid user belonging to group SystemGroup), and "Group" +# (valid user belonging to the specified group) are supported. +# +# AuthGroupName: the group name for "Group" authorization. +# +# Order: the order of Allow/Deny processing. +# +# Allow: allows access from the specified hostname, domain, IP address, or +# network. +# +# Deny: denies access from the specified hostname, domain, IP address, or +# network. +# + + + + + +# +# You may wish to limit access to printers and classes, either with Allow +# and Deny lines, or by requiring a username and password. +# + +## Require a username and password +#AuthType Basic +#AuthClass User + +## Restrict access to local domain +#Order Deny,Allow +#Deny From All +#Allow From .mydomain.com + + + +# +# You definitely will want to limit access to the administration tools. +# The default configuration requires a local connection from a user who +# is a member of group "sys" to do any admin tasks. You can change the +# group name using the SystemGroup directive. +# + +AuthType Basic +AuthClass System + +## Restrict access to local domain +Order Deny,Allow +Deny From All +Allow From 127.0.0.1 + + +# +# End of "$Id: cupsd.conf-professional 407 1999-06-17 20:02:43Z mike $". +# diff --git a/conf/mime.convs b/conf/mime.convs new file mode 100644 index 0000000000..72230bd4b4 --- /dev/null +++ b/conf/mime.convs @@ -0,0 +1,62 @@ +# +# "$Id: mime.convs 575 1999-07-30 13:57:16Z mike $" +# +# MIME converts file for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# +# Format of Lines: +# +# source/type destination/type cost filter +# +# General Notes: +# +# Currently the "cost" field is not used (all filters are assumed to +# be equally costly in terms of speed/memory). Also, a filter program +# *must* accept the standard command-line arguments (job-id, user, title, +# copies,options,[filename or stdin]) or this won't work. +# + +######################################################################## +# +# PostScript filters +# + +#application/msword application/postscript 50 mswordtops +application/pdf application/postscript 50 pdftops +application/postscript application/vnd.cups-postscript 50 pstops +application/vnd.hp-HPGL application/postscript 50 hpgltops +image/* application/vnd.cups-postscript 50 imagetops +#text/html application/postscript 50 htmltops +text/plain application/postscript 50 texttops + +######################################################################## +# +# Raster filters... +# + +image/* application/vnd.cups-raster 50 imagetoraster +application/vnd.cups-postscript application/vnd.cups-raster 50 pstoraster + +# +# End of "$Id: mime.convs 575 1999-07-30 13:57:16Z mike $". +# diff --git a/conf/mime.types b/conf/mime.types new file mode 100644 index 0000000000..e44dbcfa9b --- /dev/null +++ b/conf/mime.types @@ -0,0 +1,122 @@ +# +# "$Id: mime.types 575 1999-07-30 13:57:16Z mike $" +# +# MIME types file for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# +# Format of Lines: +# +# super/type rules +# +# "rules" can be any combination of: +# +# ( expr ) Parenthesis for expression grouping +# + Logical AND +# , or whitespace Logical OR +# ! Logical NOT +# match("pattern") Pattern match on filename +# extension Pattern match on "*.extension" +# ascii(offset,length) True if bytes are valid printable ASCII +# (CR, NL, TAB, BS, 32-126) +# printable(offset,length) True if bytes are printable 8-bit chars +# (CR, NL, TAB, BS, 32-126, 160-254) +# string(offset,"string") True if bytes are identical to string +# char(offset,value) True if byte is identical +# short(offset,value) True if 16-bit integer is identical +# int(offset,value) True if 32-bit integer is identical +# locale("string") True if current locale matches string +# +# General Notes: +# +# MIME type names are case-insensitive. Internally they are converted +# to lowercase. Multiple occurrences of a type will cause the provided +# rules to be appended to the existing definition. Type names are sorted +# in ascending order, so if two types use the same rules to resolve a type +# (e.g. doc extension for two types), the returned type will be the first +# type in the sorted list. +# +# The "printable" rule differs from the "ascii" rule in that it also +# accepts 8-bit characters in the range 160-254. +# +# String constants must be surrounded by "" if they contain whitespace. +# To instead binary data into a string, use the notation. +# + +######################################################################## +# +# Application-generated files... +# + +application/msword doc string(0,) +application/pdf pdf string(0,%PDF) +application/postscript ai eps ps string(0,%!) string(0,<04>%!) +application/vnd.hp-HPGL hpgl string(0,<1b>%) string(0,<1b>&)\ + string(0,<1b>E) string(0,<201b>)\ + string(0,BP;) string(0,IN;) string(0,DF;) + +######################################################################## +# +# Image files... +# + +image/gif gif string(0,GIF87a) string(0,GIF89a) +image/png png string(0,<89>PNG) +image/jpeg jpeg jpg jpe string(6,JFIF) +image/tiff tiff tif string(0,MM) string(0,II) +image/x-photocd pcd string(2048,PCD_IPI) +image/x-portable-anymap pnm +image/x-portable-bitmap pbm string(0,P1) string(0,P4) +image/x-portable-graymap pgm string(0,P2) string(0,P5) +image/x-portable-pixmap ppm string(0,P3) string(0,P6) +image/x-sgi-rgb rgb sgi bw icon short(0,474) +image/x-xbitmap xbm +image/x-xpixmap xpm ascii(0,1024) + string(3,"XPM") +image/x-xwindowdump xwd +image/x-sun-raster ras + +# TODO: Add Alias, SoftImage, GIMP??? files +#image/x-alias pix +#image/x-softimage +#image/x-gimp-xcf xcf xcf.gz + +######################################################################## +# +# Text files... +# + +text/html html htm printable(0,1024) +\ + (string(0,"") string(0,"%-12345X) +application/vnd.cups-raster string(0,"RaSt") string(0,"tSaR") +application/vnd.cups-raw + +# +# End of "$Id: mime.types 575 1999-07-30 13:57:16Z mike $". +# diff --git a/conf/printers.conf b/conf/printers.conf new file mode 100644 index 0000000000..b9e33c87a5 --- /dev/null +++ b/conf/printers.conf @@ -0,0 +1,89 @@ +# +# "$Id: printers.conf 334 1999-05-17 18:11:26Z mike $" +# +# Sample printer configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44145 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is a sample printer configuration file. This file is included # +# from the main configuration file (cups.conf) and lists all of the # +# printers known to the system. # +# # +######################################################################## + +# +# Each printer starts with a definition. Printer names +# can be up to 128 characters in length and are *not* case sensitive. +# +# One entry can appear in this file; if you don't +# define a default destination, the first printer or class becomes the +# default. +# + +# +# +# Info: the description for the printer. +# + +#Info Acme LaserPrint 1000 + +# +# MoreInfo: a URL for more information on the printer. +# + +#MoreInfo http://www.acme.com/lp1000.html + +# +# Location: the location of the printer. +# + +#Location Room 101 in the activities building + +# +# DeviceURI: the device URI for this printer. +# + +#DeviceURI parallel:/dev/plp +#DeviceURI serial:/dev/ttyd1?baud=38400+size=8+parity=none+flow=soft +#DeviceURI scsi:/dev/scsi/sc1d6l0 +#DeviceURI socket://hostname:port +#DeviceURI tftp://hostname/path +#DeviceURI ftp://hostname/path +#DeviceURI http://hostname[:port]/path +#DeviceURI ipp://hostname/path +#DeviceURI smb://hostname/printer + +# +# State: sets the initial state of the printer. Can be one of the +# following: +# +# Idle - Printer is available to accept new jobs. +# Stopped - Printer is disabled but accepting new jobs. +# + +#State Idle +# + +# +# End of "$Id: printers.conf 334 1999-05-17 18:11:26Z mike $". +# diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000000..a962d04c22 --- /dev/null +++ b/config.h.in @@ -0,0 +1,101 @@ +/* + * "$Id$" + * + * Configuration file for the Common UNIX Printing System (CUPS). + * + * @configure_input@ + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Version of software... + */ + +#define CUPS_SVERSION "CUPS v1.0b9" + +/* + * Where are files stored? + */ + +#define CUPS_LOCALEDIR "/usr/lib/locale" +#define CUPS_SERVERROOT "/var/cups" +#define CUPS_DATADIR "/usr/share/cups" + +/* + * Do we have various image libraries? + */ + +#undef HAVE_LIBPNG +#undef HAVE_LIBZ +#undef HAVE_LIBJPEG +#undef HAVE_LIBTIFF + +/* + * Does this machine store words in big-endian (MSB-first) order? + */ + +#undef WORDS_BIGENDIAN + +/* + * Which directory functions and headers do we use? + */ + +#undef HAVE_DIRENT_H +#undef HAVE_SYS_DIR_H +#undef HAVE_SYS_NDIR_H +#undef HAVE_NDIR_H + +/* + * Do we have ? + */ + +#undef HAVE_SHADOW_H + +/* + * Do we have ? + */ + +#undef HAVE_CRYPT_H + +/* + * Do we have the strXXX() functions? + */ + +#undef HAVE_STRDUP +#undef HAVE_STRCASECMP +#undef HAVE_STRNCASECMP + +/* + * What signal functions to use? + */ + +#undef HAVE_SIGSET +#undef HAVE_SIGACTION + +/* + * What wait functions to use? + */ + +#undef HAVE_WAITPID +#undef HAVE_WAIT3 + +/* + * End of "$Id$". + */ diff --git a/configure.in b/configure.in new file mode 100644 index 0000000000..ef76061343 --- /dev/null +++ b/configure.in @@ -0,0 +1,317 @@ +dnl +dnl "$Id$" +dnl +dnl Configuration script for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-1999 by Easy Software Products, all rights reserved. +dnl +dnl These coded instructions, statements, and computer programs are the +dnl property of Easy Software Products and are protected by Federal +dnl copyright law. Distribution and use rights are outlined in the file +dnl "LICENSE.txt" which should have been included with this file. If this +dnl file is missing or damaged please contact Easy Software Products +dnl at: +dnl +dnl Attn: CUPS Licensing Information +dnl Easy Software Products +dnl 44141 Airport View Drive, Suite 204 +dnl Hollywood, Maryland 20636-3111 USA +dnl +dnl Voice: (301) 373-9603 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +AC_INIT(cups/cups.h) +AC_CONFIG_HEADER(config.h) +AC_PREFIX_DEFAULT(/usr) + +dnl Get the operating system and version number... + +uname=`uname` +uversion=`uname -r | sed -e '1,$s/\.//g'` +if test "$uname" = "IRIX64"; then + uname="IRIX" +fi + +dnl Clear the debugging and non-shared library options unless the user asks +dnl for them... + +OPTIM="" +AC_SUBST(OPTIM) +PICFLAG=1 +CFLAGS="${CFLAGS:=}" + +AC_ARG_ENABLE(debug, [ --enable-debug turn on debugging [default=no]],[if eval "test x$enable_debug = xyes"; then + OPTIM="-g " +fi]) +AC_ARG_ENABLE(shared, [ --disable-shared turn off shared libraries [default=no]]) +if test "$disable_shared" != "yes"; then + case "$uname" in + SunOS* | UNIX_S*) + LIBCUPS="libcups.so.1" + LIBCUPSIMAGE="libcupsimage.so.1" + DSO="\$(CC) -Wl,-h,\$@ -G \$(OPTIM) -o" + ;; + HP-UX*) + LIBCUPS="libcups.sl.1" + LIBCUPSIMAGE="libcupsimage.sl.1" + DSO="ld -b -z +h \$@ -o" + ;; + OSF1* | Linux* | FreeBSD*) + LIBCUPS="libcups.so.1" + LIBCUPSIMAGE="libcupsimage.so.1" + DSO="\$(CC) -Wl,-soname,\$@ -shared \$(OPTIM) -o" + ;; + IRIX*) + LIBCUPS="libcups.so.1" + LIBCUPSIMAGE="libcupsimage.so.1" + DSO="\$(CC) -soname \$@ -shared \$(OPTIM) -o" + ;; + *) + echo "Warning: shared libraries may not be supported. Trying -shared" + echo " option with compiler." + LIBCUPS="libcups.so.1" + LIBCUPSIMAGE="libcupsimage.so.1" + DSO="\$(CC) -Wl,-soname,\$@ -shared \$(OPTIM) -o" + ;; + esac +else + PICFLAG=0 + LIBCUPS="libcups.a" + LIBCUPSIMAGE="libcupsimage.a" + DSO=":" +fi + +dnl Checks for programs... +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CPP +AC_PROG_RANLIB +AC_PATH_PROG(AR,ar) +AC_PATH_PROG(CHMOD,chmod) +AC_PATH_PROG(CP,cp) +AC_PATH_PROG(MV,mv) +AC_PATH_PROG(NROFF,nroff) +if test "$NROFF" = ""; then + AC_PATH_PROG(GROFF,groff) + if test "$GROFF" = ""; then + NROFF="echo" + else + NROFF="$GROFF -T ascii" + fi +fi +AC_PATH_PROG(HTMLDOC,htmldoc) +AC_PATH_PROG(MKDIR,mkdir) +AC_PATH_PROG(PACK,pack) +if test "$PACK" = ""; then + AC_PATH_PROG(PACK,gzip) + if test "$PACK" = ""; then + PACK="echo" + CAT="dummy" + else + PACK="$PACK -fv9" + CAT="gz" + fi +else + PACK="$PACK -f" + CAT="z" +fi +AC_SUBST(CAT) +AC_PATH_PROG(RM,rm) +AC_PATH_PROG(SED,sed) +AC_PATH_PROG(SMBCLIENT,smbclient) +if test "$SMBCLIENT" = ""; then + echo "Looking for smbclient in standard locations..." + AC_PATH_PROG(SMBCLIENT,smbclient,samba_not_detected, + /usr/samba/bin:/usr/local/samba/bin:/usr/freeware/samba/bin:/opt/samba/bin) +fi + +dnl Architecture checks... +AC_C_BIGENDIAN + +dnl Check for libraries... +AC_CHECK_LIB(c,crypt,LIBS="$LIBS",AC_CHECK_LIB(crypt,crypt)) +AC_CHECK_HEADER(crypt.h, AC_DEFINE(HAVE_CRYPT_H)) +AC_CHECK_LIB(sec,getspent) + +NETLIBS="" +AC_SUBST(NETLIBS) +AC_CHECK_LIB(socket,socket, +if test "$uname" != "IRIX"; then + NETLIBS="-lsocket" +else + echo "Not using -lsocket since you are running IRIX." +fi) +AC_CHECK_LIB(nsl,gethostbyaddr, +if test "$uname" != "IRIX"; then + NETLIBS="$NETLIBS -lnsl" +else + echo "Not using -lnsl since you are running IRIX." +fi) + +LIBJPEG="" +LIBPNG="" +LIBTIFF="" +LIBZ="" + +AC_SUBST(LIBJPEG) +AC_SUBST(LIBPNG) +AC_SUBST(LIBTIFF) +AC_SUBST(LIBZ) + +AC_CHECK_HEADER(jpeglib.h, + AC_DEFINE(HAVE_LIBJPEG) + LIBJPEG="-ljpeg") +AC_CHECK_HEADER(png.h, + AC_DEFINE(HAVE_LIBPNG) + LIBPNG="-lpng") +AC_CHECK_HEADER(tiff.h, + AC_DEFINE(HAVE_LIBTIFF) + LIBTIFF="-ltiff") +AC_CHECK_HEADER(zlib.h, + AC_DEFINE(HAVE_LIBZ) + LIBZ="-lz") + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_DIRENT +AC_CHECK_HEADER(shadow.h,AC_DEFINE(HAVE_SHADOW_H)) + +dnl Checks for string functions. +AC_CHECK_FUNCS(strdup) +AC_CHECK_FUNCS(strcasecmp) +AC_CHECK_FUNCS(strncasecmp) + +dnl Checks for signal functions. +AC_CHECK_FUNCS(sigset) +AC_CHECK_FUNCS(sigaction) + +dnl Checks for wait functions. +AC_CHECK_FUNCS(waitpid) +AC_CHECK_FUNCS(wait3) + +dnl Update compiler options... +if test -n "$GXX"; then + if test -z "$OPTIM"; then + OPTIM="-O2" + fi + if test $PICFLAG = 1; then + OPTIM="-fPIC $OPTIM" + fi +else + case $uname in + IRIX*) + if test -z "$OPTIM"; then + OPTIM="-O2" + fi + if test $uversion -ge 62; then + OPTIM="$OPTIM -n32 -mips3" + fi + ;; + HP-UX*) + if test -z "$OPTIM"; then + OPTIM="+O2" + fi + OPTIM="-Ae $OPTIM" + ;; + SunOS*) + # Solaris + if test -z "$OPTIM"; then + OPTIM="-O" + fi + if test $PICFLAG = 1; then + OPTIM="-KPIC $OPTIM" + fi + ;; + *) + # Running some other operating system; inform the user they + # should contribute the necessary options to + # cups-support@cups.org... + echo "Building CUPS with default compiler optimizations; contact" + echo "cups-support@cups.org with uname and compiler options needed" + echo "for your platform, or set the CFLAGS environment variable" + echo "before running configure." + ;; + esac +fi + +if test "$DSO" != ":"; then + # When using DSOs the image libraries are linked to libcupsimage.so + # rather than to the executables. This makes things smaller if you + # are using any static libraries, and it also allows us to distribute + # a single DSO rather than a bunch... + DSOLIBS="\$(LIBJPEG) \$(LIBPNG) \$(LIBTIFF) \$(LIBZ)" + IMGLIBS="" + + # The HP-UX and Solaris run-time linkers are EXTREMELY stupid when + # it comes to deciding where to find a DSO. Add linker options to + # tell them where to find the DSO (usually in /usr/lib... duh!) + case $uname in + HP-UX*) + LDFLAGS="$LDFLAGS -Wl,+b,$libdir,+fb" + ;; + SunOS*) + # Solaris + LDFLAGS="-R$libdir" + ;; + esac +else + DSOLIBS="" + IMGLIBS="\$(LIBJPEG) \$(LIBPNG) \$(LIBTIFF) \$(LIBZ)" +fi + +AC_SUBST(DSO) +AC_SUBST(DSOLIBS) +AC_SUBST(IMGLIBS) +AC_SUBST(LIBCUPS) +AC_SUBST(LIBCUPSIMAGE) + +dnl Fix "prefix" variable if it hasn't been specified... +if test "$prefix" = "NONE"; then + prefix="/usr" +fi + +dnl Fix "libdir" variable for IRIX 6.x... +if test "$uname" = "IRIX" -a $uversion -ge 65; then + libdir="/usr/lib32" +fi + +dnl CUPS_SERVERROOT needs special attention for the default location... +if test "$prefix" = "/usr"; then + CUPS_SERVERROOT="/var/cups" +else + CUPS_SERVERROOT="$prefix/var/cups" +fi +AC_DEFINE_UNQUOTED(CUPS_SERVERROOT, "$CUPS_SERVERROOT") +AC_SUBST(CUPS_SERVERROOT) + +dnl Set the CUPS_LOCALE directory... +case "$uname" in + Linux) + CUPS_LOCALEDIR="$prefix/share/locale" + ;; + + OSF1) + CUPS_LOCALEDIR="$prefix/lib/nls/msg" + ;; + + *) + # This is the standard System V location... + CUPS_LOCALEDIR="$prefix/lib/locale" + ;; +esac + +AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$CUPS_LOCALEDIR") +AC_SUBST(CUPS_LOCALEDIR) + +dnl Set the CUPS_DATAFILE directory... +CUPS_DATADIR="$prefix/share/cups" +AC_DEFINE_UNQUOTED(CUPS_DATADIR, "$CUPS_DATADIR") +AC_SUBST(CUPS_DATADIR) + +AC_OUTPUT(Makedefs) + +dnl +dnl End of "$Id$". +dnl diff --git a/cups.dsw b/cups.dsw new file mode 100644 index 0000000000..e332b183d5 --- /dev/null +++ b/cups.dsw @@ -0,0 +1,113 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cups"=.\cups\cups.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "hpgltops"=.\filter\hpgltops.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name cups + End Project Dependency +}}} + +############################################################################### + +Project: "image"=.\filter\image.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "pstops"=.\filter\pstops.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "testmime"=.\cups\testmime.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name cups + End Project Dependency +}}} + +############################################################################### + +Project: "testppd"=.\cups\testppd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name cups + End Project Dependency +}}} + +############################################################################### + +Project: "texttops"=.\filter\texttops.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name cups + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/cups.sh b/cups.sh new file mode 100755 index 0000000000..16c6d3fade --- /dev/null +++ b/cups.sh @@ -0,0 +1,112 @@ +#!/bin/sh +# +# "$Id$" +# +# Startup/shutdown script for the Common UNIX Printing System (CUPS). +# +# Linux chkconfig stuff: +# +# chkconfig: 2345 60 60 +# description: Startup/shutdown script for the Common UNIX \ +# Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +# See what program to use for configuration stuff... +case "`uname`" in + IRIX*) + IS_ON=/sbin/chkconfig + ;; + + *) + IS_ON=/bin/true + ;; +esac + +# The verbose flag controls the printing of the names of +# daemons as they are started. +if $IS_ON verbose; then + ECHO=echo +else + ECHO=: +fi + +# See if the CUPS server is running... +case "`uname`" in + IRIX* | HP-UX | SunOS) + pid=`ps -e | awk '{print $1,$4}' | grep cupsd | awk '{print $1}'` + ;; + OSF1) + pid=`ps -e | awk '{print $1,$5}' | grep cupsd | awk '{print $1}'` + ;; + Linux) + pid=`ps ax | awk '{print $1,$5}' | grep cupsd | awk '{print $1}'` + ;; + *) + pid="" + ;; +esac + +# Start or stop the CUPS server based upon the first argument to the script. +case $1 in + start | restart | reload) + if test "$pid" != ""; then + if $IS_ON cups; then + kill -HUP $pid + $ECHO "cups: scheduler restarted." + else + kill $pid + $ECHO "cups: scheduler stopped." + fi + else + if $IS_ON cups; then + /usr/sbin/cupsd 2>&1 >/dev/null & + $ECHO "cups: scheduler started." + fi + fi + ;; + + stop) + if test "$pid" != ""; then + kill $pid + $ECHO "cups: scheduler stopped." + fi + ;; + + status) + if test "$pid" != ""; then + echo "cups: Scheduler is running." + else + echo "cups: Scheduler is not running." + fi + ;; + + *) + echo "Usage: cups {reload|restart|start|status|stop}" + exit 1 + ;; +esac + +exit 0 + + +# +# End of "$Id$". +# diff --git a/cups/Makefile b/cups/Makefile new file mode 100644 index 0000000000..14fe89b7f5 --- /dev/null +++ b/cups/Makefile @@ -0,0 +1,150 @@ +# +# "$Id$" +# +# Support library Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Object files... +# + +LIBOBJS = emit.o filter.o http.o ipp.o language.o mark.o mime.o \ + options.o page.o ppd.o raster.o string.o type.o usersys.o \ + util.o +OBJS = $(LIBOBJS) testhttp.o testmime.o testppd.o + +# +# Header files to install... +# + +HEADERS = cups.h http.h ipp.h language.h mime.h ppd.h raster.h + +# +# Targets in this directory... +# + +TARGETS = $(LIBCUPS) testhttp testmime testppd + +# +# Make all targets... +# + +all: $(TARGETS) + +# +# Remove object and target files... +# + +clean: + rm -f $(OBJS) $(TARGETS) + +# +# Install object and target files... +# + +install: all + -$(MKDIR) $(INCLUDEDIR)/cups + $(CP) $(HEADERS) $(INCLUDEDIR)/cups + -$(MKDIR) $(LIBDIR) + $(CP) $(LIBCUPS) $(LIBDIR) + if test $(LIBCUPS) != "libcups.a"; then \ + $(LN) $(LIBCUPS) `basename $(LIBCUPS) .1`; \ + fi + +# +# libcups.so.1, libcups.sl.1 +# + +libcups.so.1 libcups.sl.1: $(LIBOBJS) ../Makedefs + echo Linking $@... + $(DSO) $@ $(LIBOBJS) + -$(LN) $@ `basename $@ .1` + +# +# libcups.a +# + +libcups.a: $(LIBOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + +# +# cups_C.h - the default POSIX locale that is compiled in. +# + +cups_C.h: ../locale/C/cups_C + echo Generating $@... + $(RM) cups_C.h + $(AWK) '{print "\"" $$0 "\","}' < ../locale/C/cups_C > cups_C.h + +emit.o: ppd.h ../config.h ../Makedefs +filter.o: mime.h ../config.h ../Makedefs +http.o: http.h ipp.h string.h ../config.h ../Makedefs +ipp.o: http.h ipp.h ../config.h ../Makedefs +language.o: cups_C.h language.h string.h ../config.h ../Makedefs +mark.o: ppd.h ../config.h ../Makedefs +mime.o: mime.h ../config.h ../Makedefs +options.o: cups.h ../config.h ../Makedefs +page.o: ppd.h ../config.h ../Makedefs +ppd.o: language.h ppd.h ../config.h ../Makedefs +raster.o: raster.h ../config.h ../Makedefs +string.o: string.h ../config.h ../Makedefs +type.o: mime.h ../config.h ../Makedefs +usersys.o: cups.h ../config.h ../Makedefs +util.o: cups.h http.h ipp.h ../config.h ../Makedefs + +# +# testhttp (dependency on static CUPS library is intentional) +# + +testhttp: testhttp.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testhttp.o libcups.a $(NETLIBS) + +testhttp.o: http.h ../Makedefs + +# +# testmime (dependency on static CUPS library is intentional) +# + +testmime: testmime.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testmime.o libcups.a + +testmime.o: mime.h ../Makedefs + +# +# testppd (dependency on static CUPS library is intentional) +# + +testppd: testppd.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testppd.o libcups.a $(NETLIBS) + +testppd.o: ppd.h ../Makedefs + +# +# End of "$Id$". +# diff --git a/cups/cups.dsp b/cups/cups.dsp new file mode 100644 index 0000000000..304345558a --- /dev/null +++ b/cups/cups.dsp @@ -0,0 +1,176 @@ +# Microsoft Developer Studio Project File - Name="cups" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=cups - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "cups.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "cups.mak" CFG="cups - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cups - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "cups - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cups - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\visualc" /I ".." /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"cups.lib" + +!ELSEIF "$(CFG)" == "cups - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "..\visualc" /I ".." /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo /out:"cupsd.lib" + +!ENDIF + +# Begin Target + +# Name "cups - Win32 Release" +# Name "cups - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\emit.c +# End Source File +# Begin Source File + +SOURCE=.\filter.c +# End Source File +# Begin Source File + +SOURCE=.\http.c +# End Source File +# Begin Source File + +SOURCE=.\ipp.c +# End Source File +# Begin Source File + +SOURCE=.\language.c +# End Source File +# Begin Source File + +SOURCE=.\mark.c +# End Source File +# Begin Source File + +SOURCE=.\mime.c +# End Source File +# Begin Source File + +SOURCE=.\options.c +# End Source File +# Begin Source File + +SOURCE=.\page.c +# End Source File +# Begin Source File + +SOURCE=.\ppd.c +# End Source File +# Begin Source File + +SOURCE=.\raster.c +# End Source File +# Begin Source File + +SOURCE=.\string.c +# End Source File +# Begin Source File + +SOURCE=.\type.c +# End Source File +# Begin Source File + +SOURCE=.\util.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\cups.h +# End Source File +# Begin Source File + +SOURCE=.\http.h +# End Source File +# Begin Source File + +SOURCE=.\ipp.h +# End Source File +# Begin Source File + +SOURCE=.\language.h +# End Source File +# Begin Source File + +SOURCE=.\mime.h +# End Source File +# Begin Source File + +SOURCE=.\ppd.h +# End Source File +# Begin Source File + +SOURCE=.\raster.h +# End Source File +# End Group +# End Target +# End Project diff --git a/cups/cups.h b/cups/cups.h new file mode 100644 index 0000000000..9219f6606c --- /dev/null +++ b/cups/cups.h @@ -0,0 +1,143 @@ +/* + * "$Id$" + * + * API definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_CUPS_H_ +# define _CUPS_CUPS_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# include + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Constants... + */ + +# define CUPS_VERSION 1.0 +# define CUPS_DATE_ANY -1 + + +/* + * Types and structures... + */ + +typedef unsigned cups_ptype_t; /**** Printer Type/Capability Bits ****/ +enum /* Not a typedef'd enum so we can OR */ +{ + CUPS_PRINTER_LOCAL = 0x0000, /* Local printer or class */ + CUPS_PRINTER_CLASS = 0x0001, /* Printer class */ + CUPS_PRINTER_REMOTE = 0x0002, /* Remote printer or class */ + CUPS_PRINTER_BW = 0x0004, /* Can do B&W printing */ + CUPS_PRINTER_COLOR = 0x0008, /* Can do color printing */ + CUPS_PRINTER_DUPLEX = 0x0010, /* Can do duplexing */ + CUPS_PRINTER_STAPLE = 0x0020, /* Can staple output */ + CUPS_PRINTER_COPIES = 0x0040, /* Can do copies */ + CUPS_PRINTER_COLLATE = 0x0080, /* Can collage copies */ + CUPS_PRINTER_PUNCH = 0x0100, /* Can punch output */ + CUPS_PRINTER_COVER = 0x0200, /* Can cover output */ + CUPS_PRINTER_BIND = 0x0400, /* Can bind output */ + CUPS_PRINTER_SORT = 0x0800, /* Can sort output */ + CUPS_PRINTER_SMALL = 0x1000, /* Can do Letter/Legal/A4 */ + CUPS_PRINTER_MEDIUM = 0x2000, /* Can do Tabloid/B/C/A3/A2 */ + CUPS_PRINTER_LARGE = 0x4000, /* Can do D/E/A1/A0 */ + CUPS_PRINTER_VARIABLE = 0x8000, /* Can do variable sizes */ + CUPS_PRINTER_IMPLICIT = 0x10000, /* Implicit class */ + CUPS_PRINTER_OPTIONS = 0xfffc /* ~(CLASS | REMOTE | IMPLICIT) */ +}; + + +/* + * Types & structures... + */ + +typedef struct /**** Printer Information ****/ +{ + char name[IPP_MAX_NAME], /* Printer or class name */ + uri[HTTP_MAX_URI]; /* Universal resource identifier */ + unsigned char info[IPP_MAX_NAME], /* Printer or class info/description */ + location[IPP_MAX_NAME]; /* Location text */ + ipp_pstate_t state; /* Printer state */ + unsigned char message[IPP_MAX_NAME]; /* State text */ + cups_ptype_t type; /* Printer type/capability codes */ +} cups_browse_t; + +typedef struct /**** Printer Options ****/ +{ + char *name; /* Name of option */ + char *value; /* Value of option */ +} cups_option_t; + + +/* + * Functions... + */ + +extern int cupsCancelJob(const char *printer, int job); +#define cupsDoRequest(http,request,resource) cupsDoFileRequest((http),(request),(resource),NULL) +extern ipp_t *cupsDoFileRequest(http_t *http, ipp_t *request, + const char *resource, const char *filename); +extern int cupsGetClasses(char ***classes); +extern const char *cupsGetDefault(void); +extern const char *cupsGetPPD(const char *printer); +extern int cupsGetPrinters(char ***printers); +extern int cupsPrintFile(const char *printer, const char *filename, + const char *title, int num_options, + cups_option_t *options); +extern char *cupsTempFile(char *filename, int len); +extern int cupsAddOption(const char *name, const char *value, + int num_options, cups_option_t **options); +extern void cupsFreeOptions(int num_options, cups_option_t *options); +extern const char *cupsGetOption(const char *name, int num_options, + cups_option_t *options); +extern int cupsParseOptions(const char *arg, int num_options, + cups_option_t **options); +extern int cupsMarkOptions(ppd_file_t *ppd, int num_options, + cups_option_t *options); + +extern const char *cupsGetPassword(const char *prompt); +extern const char *cupsServer(void); +extern const char *cupsUser(void); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_CUPS_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/cups_C.h b/cups/cups_C.h new file mode 100644 index 0000000000..ede3c9ab77 --- /dev/null +++ b/cups/cups_C.h @@ -0,0 +1,123 @@ +"us-ascii", +"OK", +"Cancel", +"Help", +"Quit", +"Close", +"Yes", +"No", +"On", +"Off", +"Save", +"Discard", +"Default", +"Options", +"More Info", +"Black", +"Color", +"Cyan", +"Magenta", +"Yellow", +"Copyright 1993-1999 by Easy Software Products, All Rights Reserved.", +"General", +"Printer", +"Image Options", +"HP-GL/2 Options", +"Extra", +"Document", +"Other", +"Print Pages: ", +"Entire Document", +"Page Range:", +"Reverse Order: ", +"Page Format: ", +" 1-Up", +" 2-Up", +" 4-Up", +"Image Scaling: ", +"Use Natural Image Size", +"Zoom by Percent", +"Zoom by PPI", +"Mirror Image: ", +"Color Saturation: ", +"Color Hue: ", +"Fit to Page: ", +"Shading: ", +"Pen Width: ", +"Gamma Correction: ", +"Brightness: ", +"Add", +"Delete", +"Modify", +"Printer URI", +"Printer Name", +"Printer Location", +"Printer Info", +"Printer Make and Model", +"Device URI", +"Formatting Page", +"Printing Page", +"Initializing Printer", +"Printer State", +"Accepting Jobs", +"Not Accepting Jobs", +"Print Jobs", +"Class", +"Local", +"Remote", +"Duplexing", +"Stapling", +"Fast Copies", +"Collated Copies", +"Hole Punching", +"Covering", +"Binding", +"Sorting", +"Small (up to 9.5x14in)", +"Medium (9.5x14in to 13x19in)", +"Large (13x19in and larger)", +"Custom Size", +"Idle", +"Processing", +"Stopped", +"All", +"Odd", +"Even Pages", +"Darker Lighter", +"Media Size", +"Media Type", +"Media Source", +"Orientation: ", +"Portrait", +"Landscape", +"Job State", +"Job Name", +"User Name", +"Priority", +"Copies", +"File Size", +"Pending", +"Output Mode", +"Resolution", +"400 Your browser sent a request that this server could not understand.", +"This server could not verify that you are authorized to access the resource.", +"You must pay to access this server.", +"You don't have permission to access the resource on this server.", +"The requested resource was not found on this server.", +"The requested method is not allowed with the resource.", +"An appropriate representation for the resource was not found on this server.", +"You don't have permission to use this server as a proxy host.", +"The request has taken too long to complete and has been aborted.", +"The requested resource has more than one value.", +"The requested resource is gone and has not been replaced.", +"The requested method requires a valid Content-Length.", +"The precondition on the request evaluated to false.", +"The request is too large for this server to process.", +"The request URI is too large for this server to process.", +"The request format is not understood by this server.", +"500 The server has detected an unrecoverable error and cannot process your request.", +"The requested method is not implemented by this server.", +"The proxy server received an invalid response from an upstream server.", +"The requested resource is currently unavailable on this server.", +"The proxy server has taken too long to respond to this server.", +"This server does not support the HTTP version required by your browser.", diff --git a/cups/debug.h b/cups/debug.h new file mode 100644 index 0000000000..415fb5f85c --- /dev/null +++ b/cups/debug.h @@ -0,0 +1,57 @@ +/* + * "$Id$" + * + * Debugging macros for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_DEBUG_H_ +# define _CUPS_DEBUG_H_ + +/* + * Include necessary headers... + */ + +# include + +/* + * The debug macros are used if you compile with DEBUG defined. + * + * Usage: + * + * DEBUG_puts("string") + * DEBUG_printf(("format string", arg, arg, ...)); + * + * Note the extra parenthesis around the DEBUG_printf macro... + */ + +# ifdef DEBUG +# define DEBUG_puts(x) puts(x) +# define DEBUG_printf(x) printf x +# else +# define DEBUG_puts(x) +# define DEBUG_printf(x) +# endif /* DEBUG */ + +#endif /* !_CUPS_DEBUG_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/emit.c b/cups/emit.c new file mode 100644 index 0000000000..b8681e69b4 --- /dev/null +++ b/cups/emit.c @@ -0,0 +1,301 @@ +/* + * "$Id$" + * + * PPD code emission routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * ppdEmit() - Emit code for marked options to a file. + * ppdEmitFd() - Emit code for marked options to a file. + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include +#include "string.h" + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +static int ppd_sort(ppd_choice_t **c1, ppd_choice_t **c2); +static int ppd_collect(ppd_file_t *ppd, ppd_section_t section, + ppd_choice_t ***choices); + + +/* + * 'ppdEmit()' - Emit code for marked options to a file. + */ + +int /* O - 0 on success, -1 on failure */ +ppdEmit(ppd_file_t *ppd, /* I - PPD file record */ + FILE *fp, /* I - File to write to */ + ppd_section_t section) /* I - Section to write */ +{ + int i, /* Looping var */ + count; /* Number of choices */ + ppd_choice_t **choices; /* Choices */ + ppd_size_t *size; /* Custom page size */ + + + if ((count = ppd_collect(ppd, section, &choices)) == 0) + return (0); + + for (i = 0; i < count; i ++) + if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) + { + /* + * Send DSC comments with option... + */ + + if (fprintf(fp, "%%%%BeginFeature: %s %s\n", + ((ppd_option_t *)choices[i]->option)->keyword, + choices[i]->choice) < 0) + { + free(choices); + return (-1); + } + + if (strcmp(((ppd_option_t *)choices[i]->option)->keyword, "PageSize") == 0 && + strcmp(choices[i]->choice, "Custom") == 0) + { + /* + * Variable size; write out standard size options (this should + * eventually be changed to use the parameter positions defined + * in the PPD file...) + */ + + size = ppdPageSize(ppd, "Custom"); + fprintf(fp, "%.0f %.0f 0 0 0\n", size->width, size->length); + + if (choices[i]->code == NULL) + { + /* + * This can happen with certain buggy PPD files that don't include + * a CustomPageSize command sequence... We just use a generic + * Level 2 command sequence... + */ + + fputs("pop pop pop\n", fp); + fputs("<>setpagedevice\n", fp); + } + } + + if (choices[i]->code != NULL && choices[i]->code[0] != '\0') + { + if (fputs(choices[i]->code, fp) < 0) + { + free(choices); + return (-1); + } + + if (choices[i]->code[strlen(choices[i]->code) - 1] != '\n') + putc('\n', fp); + } + + if (fputs("%%EndFeature\n", fp) < 0) + { + free(choices); + return (-1); + } + } + else if (fputs(choices[i]->code, fp) < 0) + { + free(choices); + return (-1); + } + + free(choices); + return (0); +} + + +/* + * 'ppdEmitFd()' - Emit code for marked options to a file. + */ + +int /* O - 0 on success, -1 on failure */ +ppdEmitFd(ppd_file_t *ppd, /* I - PPD file record */ + int fd, /* I - File to write to */ + ppd_section_t section) /* I - Section to write */ +{ + int i, /* Looping var */ + count; /* Number of choices */ + ppd_choice_t **choices; /* Choices */ + char buf[1024]; /* Output buffer for feature */ + + + if ((count = ppd_collect(ppd, section, &choices)) == 0) + return (0); + + for (i = 0; i < count; i ++) + if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL) + { + /* + * Send DSC comments with option... + */ + + sprintf(buf, "%%%%BeginFeature: %s %s\n", + ((ppd_option_t *)choices[i]->option)->keyword, choices[i]->choice); + + if (write(fd, buf, strlen(buf)) < 1) + { + free(choices); + return (-1); + } + + if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1) + { + free(choices); + return (-1); + } + + if (write(fd, "%%EndFeature\n", 13) < 1) + { + free(choices); + return (-1); + } + } + else if (write(fd, choices[i]->code, strlen(choices[i]->code)) < 1) + { + free(choices); + return (-1); + } + + free(choices); + return (0); +} + + +/* + * 'ppd_sort()' - Sort options by ordering numbers... + */ + +static int /* O - -1 if c1 < c2, 0 if equal, 1 otherwise */ +ppd_sort(ppd_choice_t **c1, /* I - First choice */ + ppd_choice_t **c2) /* I - Second choice */ +{ + if (((ppd_option_t *)(*c1)->option)->order < ((ppd_option_t *)(*c2)->option)->order) + return (-1); + else if (((ppd_option_t *)(*c1)->option)->order > ((ppd_option_t *)(*c2)->option)->order) + return (1); + else + return (0); +} + + +/* + * 'ppd_collect()' - Collect all marked options that reside in the specified + * section. + */ + +static int /* O - Number of options marked */ +ppd_collect(ppd_file_t *ppd, /* I - PPD file data */ + ppd_section_t section, /* I - Section to collect */ + ppd_choice_t ***choices) /* O - Pointers to choices */ +{ + int i, j, k, m; /* Looping vars */ + ppd_group_t *g, /* Current group */ + *sg; /* Current sub-group */ + ppd_option_t *o; /* Current option */ + ppd_choice_t *c; /* Current choice */ + int count; /* Number of choices collected */ + ppd_choice_t **collect; /* Collected choices */ + + + if (ppd == NULL) + return (0); + + /* + * Allocate memory for up to 1000 selected choices... + */ + + count = 0; + collect = calloc(sizeof(ppd_choice_t *), 1000); + + /* + * Loop through all options and add choices as needed... + */ + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + { + for (j = g->num_options, o = g->options; j > 0; j --, o ++) + if (o->section == section) + for (k = o->num_choices, c = o->choices; k > 0; k --, c ++) + if (c->marked && count < 1000) + { + collect[count] = c; + count ++; + } + + for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++) + for (k = sg->num_options, o = sg->options; k > 0; k --, o ++) + if (o->section == section) + for (m = o->num_choices, c = o->choices; m > 0; m --, c ++) + if (c->marked && count < 1000) + { + collect[count] = c; + count ++; + } + } + + /* + * If we have more than 1 marked choice, sort them... + */ + + if (count > 1) + qsort(collect, count, sizeof(ppd_choice_t *), + (int (*)(const void *, const void *))ppd_sort); + + /* + * Return the array and number of choices; if 0, free the array since + * it isn't needed. + */ + + if (count > 0) + { + *choices = collect; + return (count); + } + else + { + *choices = NULL; + free(collect); + return (0); + } +} + + +/* + * End of "$Id$". + */ diff --git a/cups/filter.c b/cups/filter.c new file mode 100644 index 0000000000..39e17091b1 --- /dev/null +++ b/cups/filter.c @@ -0,0 +1,297 @@ +/* + * "$Id$" + * + * File type conversion routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * mimeAddFilter() - Add a filter to the current MIME database. + * mimeFilter() - Find the fastest way to convert from one type to another. + * compare() - Compare two filter types... + * lookup() - Lookup a filter... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#include "string.h" +#include "mime.h" + + +/* + * Local functions... + */ + +static int compare(mime_filter_t *, mime_filter_t *); +static mime_filter_t *lookup(mime_t *, mime_type_t *, mime_type_t *); + + +/* + * 'mimeAddFilter()' - Add a filter to the current MIME database. + */ + +mime_filter_t * /* O - New filter */ +mimeAddFilter(mime_t *mime, /* I - MIME database */ + mime_type_t *src, /* I - Source type */ + mime_type_t *dst, /* I - Destination type */ + int cost, /* I - Relative time/resource cost */ + const char *filter) /* I - Filter program to run */ +{ + mime_filter_t *temp; /* New filter */ + + + /* + * Range-check the input... + */ + + if (mime == NULL || src == NULL || dst == NULL || filter == NULL) + return (NULL); + + if (strlen(filter) > (MIME_MAX_FILTER - 1)) + return (NULL); + + /* + * See if we already have an existing filter for the given source and + * destination... + */ + + if ((temp = lookup(mime, src, dst)) != NULL) + { + /* + * Yup, does the existing filter have a higher cost? If so, copy the + * filter and cost to the existing filter entry and return it... + */ + + if (temp->cost > cost) + { + temp->cost = cost; + strcpy(temp->filter, filter); + } + } + else + { + /* + * Nope, add a new one... + */ + + if (mime->num_filters == 0) + temp = malloc(sizeof(mime_filter_t)); + else + temp = realloc(mime->filters, sizeof(mime_filter_t) * (mime->num_filters + 1)); + + if (temp == NULL) + return (NULL); + + mime->filters = temp; + temp += mime->num_filters; + mime->num_filters ++; + + /* + * Copy the information over and sort if necessary... + */ + + temp->src = src; + temp->dst = dst; + temp->cost = cost; + strcpy(temp->filter, filter); + + if (mime->num_filters > 1) + qsort(mime->filters, mime->num_filters, sizeof(mime_filter_t), + (int (*)(const void *, const void *))compare); + } + + /* + * Return the new/updated filter... + */ + + return (temp); +} + + +/* + * 'mimeFilter()' - Find the fastest way to convert from one type to another. + */ + +mime_filter_t * /* O - Array of filters to run */ +mimeFilter(mime_t *mime, /* I - MIME database */ + mime_type_t *src, /* I - Source file type */ + mime_type_t *dst, /* I - Destination file type */ + int *num_filters) /* O - Number of filters to run */ +{ + int i, j, /* Looping vars */ + num_temp, /* Number of temporary filters */ + num_mintemp, /* Number of filters in the minimum */ + cost, /* Current cost */ + mincost; /* Current minimum */ + mime_filter_t *temp, /* Temporary filter */ + *mintemp, /* Current minimum */ + *mincurrent, /* Current filter for minimum */ + *current, /* Current filter */ + *filters; /* Filters to use */ + + + /* + * Range-check the input... + */ + + if (mime == NULL || src == NULL || dst == NULL || num_filters == NULL) + return (NULL); + + *num_filters = 0; + + /* + * See if there is a filter that can convert the files directly... + */ + + if ((temp = lookup(mime, src, dst)) != NULL) + { + /* + * Got a direct filter! + */ + + if ((filters = (mime_filter_t *)malloc(sizeof(mime_filter_t))) == NULL) + return (NULL); + + memcpy(filters, temp, sizeof(mime_filter_t)); + *num_filters = 1; + return (filters); + } + + /* + * OK, now look for filters from the source type to any other type... + */ + + mincost = 9999999; + mintemp = NULL; + + for (i = mime->num_filters, current = mime->filters; i > 0; i --, current ++) + if (current->src == src) + { + /* + * See if we have any filters that can convert from the destination type + * of this filter to the final type... + */ + + if ((temp = mimeFilter(mime, current->dst, dst, &num_temp)) == NULL) + continue; + + /* + * Found a match; see if this one is less costly than the last (if + * any...) + */ + + for (j = 0, cost = 0; j < num_temp; j ++) + cost += temp->cost; + + if (cost < mincost) + { + if (mintemp != NULL) + free(mintemp); + + mincost = cost; + mintemp = temp; + num_mintemp = num_temp; + mincurrent = current; + } + else + free(temp); + } + + if (mintemp != NULL) + { + /* + * Hey, we got a match! Add the current filter to the beginning of the + * filter list... + */ + + filters = (mime_filter_t *)realloc(mintemp, sizeof(mime_filter_t) * + (num_mintemp + 1)); + + if (filters == NULL) + { + *num_filters = 0; + return (NULL); + } + + memmove(filters + 1, filters, num_mintemp * sizeof(mime_filter_t)); + memcpy(filters, mincurrent, sizeof(mime_filter_t)); + + *num_filters = num_mintemp + 1; + + return (filters); + } + + return (NULL); +} + + +/* + * 'compare()' - Compare two filter types... + */ + +static int /* O - Comparison result */ +compare(mime_filter_t *f0, /* I - First filter */ + mime_filter_t *f1) /* I - Second filter */ +{ + int i; /* Result of comparison */ + + + if ((i = strcmp(f0->src->super, f1->src->super)) == 0) + if ((i = strcmp(f0->src->type, f1->src->type)) == 0) + if ((i = strcmp(f0->dst->super, f1->dst->super)) == 0) + i = strcmp(f0->dst->type, f1->dst->type); + + return (i); +} + + +/* + * 'lookup()' - Lookup a filter... + */ + +static mime_filter_t * /* O - Filter for src->dst */ +lookup(mime_t *mime, /* I - MIME database */ + mime_type_t *src, /* I - Source type */ + mime_type_t *dst) /* I - Destination type */ +{ + mime_filter_t key; /* Key record for filter search */ + + + if (mime->num_filters == 0) + return (NULL); + + key.src = src; + key.dst = dst; + + return ((mime_filter_t *)bsearch(&key, mime->filters, mime->num_filters, + sizeof(mime_filter_t), + (int (*)(const void *, const void *))compare)); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/http.c b/cups/http.c new file mode 100644 index 0000000000..3fd09f3063 --- /dev/null +++ b/cups/http.c @@ -0,0 +1,1473 @@ +/* + * "$Id$" + * + * HTTP routines for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These statusd instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * httpInitialize() - Initialize the HTTP interface library and set the + * default HTTP proxy (if any). + * httpCheck() - Check to see if there is a pending response from + * the server. + * httpClose() - Close an HTTP connection... + * httpConnect() - Connect to a HTTP server. + * httpReconnect() - Reconnect to a HTTP server... + * httpSeparate() - Separate a Universal Resource Identifier into its + * components. + * httpSetField() - Set the value of an HTTP header. + * httpDelete() - Send a DELETE request to the server. + * httpGet() - Send a GET request to the server. + * httpHead() - Send a HEAD request to the server. + * httpOptions() - Send an OPTIONS request to the server. + * httpPost() - Send a POST request to the server. + * httpPut() - Send a PUT request to the server. + * httpTrace() - Send an TRACE request to the server. + * httpFlush() - Flush data from a HTTP connection. + * httpRead() - Read data from a HTTP connection. + * httpWrite() - Write data to a HTTP connection. + * httpGets() - Get a line of text from a HTTP connection. + * httpPrintf() - Print a formatted string to a HTTP connection. + * httpStatus() - Return a short string describing a HTTP status code. + * httpGetDateString() - Get a formatted date/time string from a time value. + * httpGetDateTime() - Get a time value from a formatted date/time string. + * httpUpdate() - Update the current HTTP state for incoming data. + * httpDecode64() - Base64-decode a string. + * httpEncode64() - Base64-encode a string. + * httpGetLength() - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + * http_field() - Return the field index for a field name. + * http_send() - Send a request with all fields and the trailing + * blank line. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include "string.h" +#include +#include + +#include "http.h" +#include "ipp.h" +#include "debug.h" + +#if !defined(WIN32) && !defined(__EMX__) +# include +#endif /* !WIN32 && !__EMX__ */ + +/* + * Some operating systems have done away with the Fxxxx constants for + * the fcntl() call; this works around that "feature"... + */ + +#ifndef FNONBLK +# define FNONBLK O_NONBLOCK +#endif /* !FNONBLK */ + + +/* + * Local functions... + */ + +static http_field_t http_field(const char *name); +static int http_send(http_t *http, http_state_t request, + const char *uri); + + +/* + * Local globals... + */ + +static const char *http_fields[] = + { + "Accept-Language", + "Accept-Ranges", + "Authorization", + "Connection", + "Content-Encoding", + "Content-Language", + "Content-Length", + "Content-Location", + "Content-MD5", + "Content-Range", + "Content-Type", + "Content-Version", + "Date", + "Host", + "If-Modified-Since", + "If-Unmodified-since", + "Keep-Alive", + "Last-Modified", + "Link", + "Location", + "Range", + "Referer", + "Retry-After", + "Transfer-Encoding", + "Upgrade", + "User-Agent", + "WWW-Authenticate" + }; +static const char *days[7] = + { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + }; +static const char *months[12] = + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + +/* + * 'httpInitialize()' - Initialize the HTTP interface library and set the + * default HTTP proxy (if any). + */ + +void +httpInitialize(void) +{ +#if defined(WIN32) || defined(__EMX__) + WSADATA winsockdata; /* WinSock data */ + static int initialized = 0;/* Has WinSock been initialized? */ + + + if (!initialized) + WSAStartup(MAKEWORD(1,1), &winsockdata); +#elif defined(HAVE_SIGSET) + sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) + struct sigaction action; /* POSIX sigaction data */ + + + /* + * Ignore SIGPIPE signals... + */ + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* WIN32 || __EMX__ */ +} + + +/* + * 'httpCheck()' - Check to see if there is a pending response from the server. + */ + +int /* O - 0 = no data, 1 = data available */ +httpCheck(http_t *http) /* I - HTTP connection */ +{ + fd_set input; /* Input set for select() */ + struct timeval timeout; /* Timeout */ + + + /* + * First see if there is data in the buffer... + */ + + if (http == NULL) + return (0); + + if (http->used) + return (1); + + /* + * Then try doing a select() to poll the socket... + */ + + FD_ZERO(&input); + FD_SET(http->fd, &input); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + return (select(http->fd + 1, &input, NULL, NULL, &timeout) > 0); +} + + +/* + * 'httpClose()' - Close an HTTP connection... + */ + +void +httpClose(http_t *http) /* I - Connection to close */ +{ + if (http == NULL) + return; + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif /* WIN32 */ + + free(http); +} + + +/* + * 'httpConnect()' - Connect to a HTTP server. + */ + +http_t * /* O - New HTTP connection */ +httpConnect(const char *host, /* I - Host to connect to */ + int port) /* I - Port number */ +{ + http_t *http; /* New HTTP connection */ + struct hostent *hostaddr; /* Host address data */ + + + httpInitialize(); + + /* + * Lookup the host... + */ + + if ((hostaddr = gethostbyname(host)) == NULL) + return (NULL); + + /* + * Allocate memory for the structure... + */ + + http = calloc(sizeof(http_t), 1); + if (http == NULL) + return (NULL); + + http->version = HTTP_1_1; + http->blocking = 1; + http->activity = time(NULL); + + /* + * Copy the hostname and port and then "reconnect"... + */ + + strcpy(http->hostname, host); + memset((char *)&(http->hostaddr), 0, sizeof(http->hostaddr)); + memcpy((char *)&(http->hostaddr.sin_addr), hostaddr->h_addr, hostaddr->h_length); + http->hostaddr.sin_family = hostaddr->h_addrtype; +#ifdef WIN32 + http->hostaddr.sin_port = htons((u_short)port); +#else + http->hostaddr.sin_port = htons(port); +#endif /* WIN32 */ + if (httpReconnect(http)) + { + free(http); + return (NULL); + } + else + return (http); +} + + +/* + * 'httpReconnect()' - Reconnect to a HTTP server... + */ + +int /* O - 0 on success, non-zero on failure */ +httpReconnect(http_t *http) /* I - HTTP data */ +{ + int val; /* Socket option value */ + + + /* + * Close any previously open socket... + */ + + if (http->fd) +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif /* WIN32 */ + + /* + * Create the socket and set options to allow reuse. + */ + + if ((http->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + http->error = errno; + return (-1); + } + +#ifdef FD_CLOEXEC + fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting * + * other processes... */ +#endif /* FD_CLOEXEC */ + + val = 1; + setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); + +#ifdef SO_REUSEPORT + val = 1; + setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); +#endif /* SO_REUSEPORT */ + + /* + * Connect to the server... + */ + + if (connect(http->fd, (struct sockaddr *)&(http->hostaddr), + sizeof(http->hostaddr)) < 0) + { + http->error = errno; + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif + + return (-1); + } + else + http->error = 0; + + return (0); +} + + +/* + * 'httpSeparate()' - Separate a Universal Resource Identifier into its + * components. + */ + +void +httpSeparate(const char *uri, /* I - Universal Resource Identifier */ + char *method, /* O - Method (http, https, etc.) */ + char *username, /* O - Username */ + char *host, /* O - Hostname */ + int *port, /* O - Port number to use */ + char *resource) /* O - Resource/filename */ +{ + char *ptr; /* Pointer into string... */ + + + if (uri == NULL || method == NULL || username == NULL || host == NULL || + port == NULL || resource == NULL) + return; + + /* + * Grab the method portion of the URI... + */ + + ptr = host; + while (*uri != ':' && *uri != '\0') + *ptr++ = *uri++; + + *ptr = '\0'; + if (*uri == ':') + uri ++; + + /* + * If the method contains a period or slash, then it's probably + * hostname/filename... + */ + + if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0') + { + if ((ptr = strchr(host, '/')) != NULL) + { + strcpy(resource, ptr); + *ptr = '\0'; + } + else + resource[0] = '\0'; + + if (isdigit(*uri)) + { + /* + * OK, we have "hostname:port[/resource]"... + */ + + *port = strtol(uri, (char **)&uri, 10); + + if (*uri == '/') + strcpy(resource, uri); + } + else + *port = 0; + + strcpy(method, "http"); + username[0] = '\0'; + return; + } + else + strcpy(method, host); + + /* + * If the method starts with less than 2 slashes then it is a local resource... + */ + + if (strncmp(uri, "//", 2) != 0) + { + strcpy(resource, uri); + username[0] = '\0'; + host[0] = '\0'; + *port = 0; + return; + } + + /* + * Grab the hostname... + */ + + while (*uri == '/') + uri ++; + + ptr = host; + while (*uri != ':' && *uri != '@' && *uri != '/' && *uri != '\0') + *ptr ++ = *uri ++; + + *ptr = '\0'; + + if (*uri == '@') + { + /* + * Got a username... + */ + + strcpy(username, host); + + ptr = host; + while (*uri != ':' && *uri != '/' && *uri != '\0') + *ptr ++ = *uri ++; + + *ptr = '\0'; + } + else + username[0] = '\0'; + + if (*uri == '\0') + { + /* + * Hostname but no port or path... + */ + + *port = 0; + resource[0] = '/'; + resource[1] = '\0'; + return; + } + else if (*uri == ':') + { + /* + * Parse port number... + */ + + *port = 0; + uri ++; + while (isdigit(*uri)) + { + *port = (*port * 10) + *uri - '0'; + uri ++; + } + } + else + { + /* + * Figure out the default port number based on the method... + */ + + if (strcasecmp(method, "http") == 0) + *port = 80; + else if (strcasecmp(method, "https") == 0) + *port = 443; + else if (strcasecmp(method, "ipp") == 0) /* Not registered yet... */ + *port = ippPort(); + else if (strcasecmp(method, "socket") == 0) /* Not registered yet... */ + *port = 9100; + else + *port = 0; + } + + /* + * The remaining portion is the resource string... + */ + + strcpy(resource, uri); +} + + +/* + * 'httpSetField()' - Set the value of an HTTP header. + */ + +void +httpSetField(http_t *http, /* I - HTTP data */ + http_field_t field, /* I - Field index */ + const char *value) /* I - Value */ +{ + strncpy(http->fields[field], value, HTTP_MAX_VALUE - 1); + http->fields[field][HTTP_MAX_VALUE - 1] = '\0'; +} + + +/* + * 'httpDelete()' - Send a DELETE request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpDelete(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI to delete */ +{ + return (http_send(http, HTTP_DELETE, uri)); +} + + +/* + * 'httpGet()' - Send a GET request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpGet(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI to get */ +{ + return (http_send(http, HTTP_GET, uri)); +} + + +/* + * 'httpHead()' - Send a HEAD request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpHead(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for head */ +{ + return (http_send(http, HTTP_HEAD, uri)); +} + + +/* + * 'httpOptions()' - Send an OPTIONS request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpOptions(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for options */ +{ + return (http_send(http, HTTP_OPTIONS, uri)); +} + + +/* + * 'httpPost()' - Send a POST request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpPost(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for post */ +{ + httpGetLength(http); + + return (http_send(http, HTTP_POST, uri)); +} + + +/* + * 'httpPut()' - Send a PUT request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpPut(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI to put */ +{ + httpGetLength(http); + + return (http_send(http, HTTP_PUT, uri)); +} + + +/* + * 'httpTrace()' - Send an TRACE request to the server. + */ + +int /* O - Status of call (0 = success) */ +httpTrace(http_t *http, /* I - HTTP data */ + const char *uri) /* I - URI for trace */ +{ + return (http_send(http, HTTP_TRACE, uri)); +} + + +/* + * 'httpFlush()' - Flush data from a HTTP connection. + */ + +void +httpFlush(http_t *http) /* I - HTTP data */ +{ + char buffer[8192]; /* Junk buffer */ + + + while (httpRead(http, buffer, sizeof(buffer)) > 0); +} + + +/* + * 'httpRead()' - Read data from a HTTP connection. + */ + +int /* O - Number of bytes read */ +httpRead(http_t *http, /* I - HTTP data */ + char *buffer, /* I - Buffer for data */ + int length) /* I - Maximum number of bytes */ +{ + int bytes; /* Bytes read */ + char len[32]; /* Length string */ + + + DEBUG_printf(("httpRead(%08x, %08x, %d)\n", http, buffer, length)); + + if (http == NULL || buffer == NULL) + return (-1); + + http->activity = time(NULL); + + if (length <= 0) + return (0); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED && + http->data_remaining <= 0 && + (http->state == HTTP_GET_SEND || http->state == HTTP_POST_RECV || + http->state == HTTP_POST_SEND || http->state == HTTP_PUT_RECV)) + { + if (httpGets(len, sizeof(len), http) == NULL) + return (0); + + http->data_remaining = strtol(len, NULL, 16); + } + + DEBUG_printf(("httpRead: data_remaining = %d\n", http->data_remaining)); + + if (http->data_remaining == 0) + { + /* + * A zero-length chunk ends a transfer; unless we are reading POST + * data, go idle... + */ + + if (http->data_encoding == HTTP_ENCODE_CHUNKED && + (http->state == HTTP_GET_SEND || http->state == HTTP_POST_RECV || + http->state == HTTP_POST_SEND || http->state == HTTP_PUT_RECV)) + httpGets(len, sizeof(len), http); + + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + + return (0); + } + else if (length > http->data_remaining) + length = http->data_remaining; + + if (http->used > 0) + { + if (length > http->used) + length = http->used; + + bytes = length; + + DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes)); + + memcpy(buffer, http->buffer, length); + http->used -= length; + + if (http->used > 0) + memcpy(http->buffer, http->buffer + length, http->used); + } + else + { + DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length)); + bytes = recv(http->fd, buffer, length, 0); + DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes)); + } + + if (bytes > 0) + http->data_remaining -= bytes; + else if (bytes < 0) + http->error = errno; + + if (http->data_remaining == 0) + { + if (http->data_encoding == HTTP_ENCODE_CHUNKED && + (http->state == HTTP_GET_SEND || http->state == HTTP_POST_RECV || + http->state == HTTP_POST_SEND || http->state == HTTP_PUT_RECV)) + httpGets(len, sizeof(len), http); + + if (http->data_encoding != HTTP_ENCODE_CHUNKED) + { + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + } + } + + return (bytes); +} + + +/* + * 'httpWrite()' - Write data to a HTTP connection. + */ + +int /* O - Number of bytes written */ +httpWrite(http_t *http, /* I - HTTP data */ + const char *buffer, /* I - Buffer for data */ + int length) /* I - Number of bytes to write */ +{ + int tbytes, /* Total bytes sent */ + bytes; /* Bytes sent */ + char len[32]; /* Length string */ + + + if (http == NULL || buffer == NULL) + return (-1); + + http->activity = time(NULL); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED && + (http->state == HTTP_GET_SEND || http->state == HTTP_POST_RECV || + http->state == HTTP_POST_SEND || http->state == HTTP_PUT_RECV)) + if (httpPrintf(http, "%x\r\n", length) < 0) + return (-1); + + if (length == 0) + { + /* + * A zero-length chunk ends a transfer; unless we are sending POST + * data, go idle... + */ + + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + + return (0); + } + + tbytes = 0; + + while (length > 0) + { + bytes = send(http->fd, buffer, length, 0); + if (bytes < 0) + { + DEBUG_puts("httpWrite: error writing data...\n"); + + return (-1); + } + + buffer += bytes; + tbytes += bytes; + length -= bytes; + if (http->data_encoding == HTTP_ENCODE_LENGTH) + http->data_remaining -= bytes; + } + + if (http->data_encoding == HTTP_ENCODE_CHUNKED && + (http->state == HTTP_GET_SEND || http->state == HTTP_POST_RECV || + http->state == HTTP_POST_SEND || http->state == HTTP_PUT_RECV)) + if (httpPrintf(http, "\r\n") < 0) + return (-1); + + if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH) + { + /* + * Finished with the transfer; unless we are sending POST data, go idle... + */ + + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + } + + DEBUG_printf(("httpWrite: wrote %d bytes...\n", tbytes)); + + return (tbytes); +} + + +/* + * 'httpGets()' - Get a line of text from a HTTP connection. + */ + +char * /* O - Line or NULL */ +httpGets(char *line, /* I - Line to read into */ + int length, /* I - Max length of buffer */ + http_t *http) /* I - HTTP data */ +{ + char *lineptr, /* Pointer into line */ + *bufptr, /* Pointer into input buffer */ + *bufend; /* Pointer to end of buffer */ + int bytes; /* Number of bytes read */ + + + DEBUG_printf(("httpGets(%08x, %d, %08x)\n", line, length, http)); + + if (http == NULL || line == NULL) + return (NULL); + + /* + * Pre-scan the buffer and see if there is a newline in there... + */ + + errno = 0; + + do + { + bufptr = http->buffer; + bufend = http->buffer + http->used; + + while (bufptr < bufend) + if (*bufptr == 0x0a) + break; + else + bufptr ++; + + if (bufptr >= bufend) + { + /* + * No newline; see if there is more data to be read... + */ + + if ((bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0)) < 0) + { + /* + * Nope, can't get a line this time... + */ + + if (errno != http->error) + { + http->error = errno; + continue; + } + + DEBUG_printf(("httpGets(): recv() error %d!\n", errno)); + + return (NULL); + } + else if (bytes == 0) + { + if (http->blocking) + http->error = EPIPE; + + return (NULL); + } + + /* + * Yup, update the amount used and the end pointer... + */ + + http->used += bytes; + bufend += bytes; + } + } + while (bufptr >= bufend); + + http->activity = time(NULL); + + /* + * Read a line from the buffer... + */ + + lineptr = line; + bufptr = http->buffer; + bytes = 0; + + while (bufptr < bufend && bytes < length) + { + bytes ++; + + if (*bufptr == 0x0a) + { + bufptr ++; + *lineptr = '\0'; + + http->used -= bytes; + if (http->used > 0) + memcpy(http->buffer, bufptr, http->used); + + DEBUG_printf(("httpGets(): Returning \"%s\"\n", line)); + return (line); + } + else if (*bufptr == 0x0d) + bufptr ++; + else + *lineptr++ = *bufptr++; + } + + DEBUG_puts("httpGets(): No new line available!"); + + return (NULL); +} + + +/* + * 'httpPrintf()' - Print a formatted string to a HTTP connection. + */ + +int /* O - Number of bytes written */ +httpPrintf(http_t *http, /* I - HTTP data */ + const char *format, /* I - printf-style format string */ + ...) /* I - Additional args as needed */ +{ + int bytes, /* Number of bytes to write */ + nbytes, /* Number of bytes written */ + tbytes; /* Number of bytes all together */ + char buf[HTTP_MAX_BUFFER], /* Buffer for formatted string */ + *bufptr; /* Pointer into buffer */ + va_list ap; /* Variable argument pointer */ + + + va_start(ap, format); + bytes = vsprintf(buf, format, ap); + va_end(ap); + + DEBUG_printf(("httpPrintf: %s", buf)); + + for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes) + if ((nbytes = send(http->fd, bufptr, bytes - tbytes, 0)) < 0) + return (-1); + + return (bytes); +} + + +/* + * 'httpStatus()' - Return a short string describing a HTTP status code. + */ + +const char * /* O - String or NULL */ +httpStatus(http_status_t status) /* I - HTTP status code */ +{ + switch (status) + { + case HTTP_OK : + return ("OK"); + case HTTP_CREATED : + return ("Created"); + case HTTP_ACCEPTED : + return ("Accepted"); + case HTTP_NO_CONTENT : + return ("No Content"); + case HTTP_NOT_MODIFIED : + return ("Not Modified"); + case HTTP_BAD_REQUEST : + return ("Bad Request"); + case HTTP_UNAUTHORIZED : + return ("Unauthorized"); + case HTTP_FORBIDDEN : + return ("Forbidden"); + case HTTP_NOT_FOUND : + return ("Not Found"); + case HTTP_REQUEST_TOO_LARGE : + return ("Request Entity Too Large"); + case HTTP_URI_TOO_LONG : + return ("URI Too Long"); + case HTTP_NOT_IMPLEMENTED : + return ("Not Implemented"); + case HTTP_NOT_SUPPORTED : + return ("Not Supported"); + default : + return ("Unknown"); + } +} + + +/* + * 'httpGetDateString()' - Get a formatted date/time string from a time value. + */ + +const char * /* O - Date/time string */ +httpGetDateString(time_t t) /* I - UNIX time */ +{ + struct tm *tdate; + static char datetime[256]; + + + tdate = gmtime(&t); + sprintf(datetime, "%s, %02d %s %d %02d:%02d:%02d GMT", + days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon], + tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec); + + return (datetime); +} + + +/* + * 'httpGetDateTime()' - Get a time value from a formatted date/time string. + */ + +time_t /* O - UNIX time */ +httpGetDateTime(const char *s) /* I - Date/time string */ +{ + int i; /* Looping var */ + struct tm tdate; /* Time/date structure */ + char mon[16]; /* Abbreviated month name */ + int day, year; /* Day of month and year */ + int hour, min, sec; /* Time */ + + + if (sscanf(s, "%*s%d%s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6) + return (0); + + for (i = 0; i < 12; i ++) + if (strcasecmp(mon, months[i]) == 0) + break; + + if (i >= 12) + return (0); + + tdate.tm_mon = i; + tdate.tm_mday = day; + tdate.tm_year = year - 1900; + tdate.tm_hour = hour; + tdate.tm_min = min; + tdate.tm_sec = sec; + tdate.tm_isdst = 0; + + return (mktime(&tdate)); +} + + +/* + * 'httpUpdate()' - Update the current HTTP state for incoming data. + */ + +http_status_t /* O - HTTP status */ +httpUpdate(http_t *http) /* I - HTTP data */ +{ + char line[1024], /* Line from connection... */ + *value; /* Pointer to value on line */ + http_field_t field; /* Field index */ + int major, minor; /* HTTP version numbers */ + http_status_t status; /* Authorization status */ + + + DEBUG_printf(("httpUpdate(%08x)\n", http)); + + /* + * If we haven't issued any commands, then there is nothing to "update"... + */ + + if (http->state == HTTP_WAITING) + return (HTTP_CONTINUE); + + /* + * Grab all of the lines we can from the connection... + */ + + while (httpGets(line, sizeof(line), http) != NULL) + { + DEBUG_puts(line); + + if (line[0] == '\0') + { + /* + * Blank line means the start of the data section (if any). Return + * the result code, too... + * + * If we get status 100 (HTTP_CONTINUE), then we *don't* change states. + * Instead, we just return HTTP_CONTINUE to the caller and keep on + * tryin'... + */ + + if (http->status == HTTP_CONTINUE) + return (http->status); + + httpGetLength(http); + + switch (http->state) + { + case HTTP_GET : + case HTTP_POST : + case HTTP_POST_RECV : + case HTTP_PUT : + http->state ++; + break; + + default : + http->state = HTTP_WAITING; + break; + } + + return (http->status); + } + else if (strncmp(line, "HTTP/", 5) == 0) + { + /* + * Got the beginning of a response... + */ + + if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3) + return (HTTP_ERROR); + + http->version = (http_version_t)(major * 100 + minor); + http->status = status; + } + else if ((value = strchr(line, ':')) != NULL) + { + /* + * Got a value... + */ + + *value++ = '\0'; + while (isspace(*value)) + value ++; + + /* + * Be tolerants of servers that send unknown attribute fields... + */ + + if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN) + { + DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line)); + continue; + } + + httpSetField(http, field, value); + } + else + return (HTTP_ERROR); + } + + /* + * See if there was an error... + */ + + if (http->error) + return (HTTP_ERROR); + + /* + * If we haven't already returned, then there is nothing new... + */ + + return (HTTP_CONTINUE); +} + + +/* + * 'httpDecode64()' - Base64-decode a string. + */ + +char * /* O - Decoded string */ +httpDecode64(char *out, /* I - String to write to */ + const char *in) /* I - String to read from */ +{ + int pos, /* Bit position */ + base64; /* Value of this character */ + char *outptr; /* Output pointer */ + + + for (outptr = out, pos = 0; *in != '\0'; in ++) + { + /* + * Decode this character into a number from 0 to 63... + */ + + if (*in >= 'A' && *in <= 'Z') + base64 = *in - 'A'; + else if (*in >= 'a' && *in <= 'z') + base64 = *in - 'a' + 26; + else if (*in >= '0' && *in <= '9') + base64 = *in - '0' + 52; + else if (*in == '+') + base64 = 62; + else if (*in == '/') + base64 = 63; + else if (*in == '=') + break; + else + continue; + + /* + * Store the result in the appropriate chars... + */ + + switch (pos) + { + case 0 : + *outptr = base64 << 2; + pos ++; + break; + case 1 : + *outptr++ |= (base64 >> 4) & 3; + *outptr = (base64 << 4) & 255; + pos ++; + break; + case 2 : + *outptr++ |= (base64 >> 2) & 15; + *outptr = (base64 << 6) & 255; + pos ++; + break; + case 3 : + *outptr++ |= base64; + pos = 0; + break; + } + } + + *outptr = '\0'; + + /* + * Return the decoded string... + */ + + return (out); +} + + +/* + * 'httpEncode64()' - Base64-encode a string. + */ + +char * /* O - Encoded string */ +httpEncode64(char *out, /* I - String to write to */ + const char *in) /* I - String to read from */ +{ + char *outptr; /* Output pointer */ + static char base64[] = /* Base64 characters... */ + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/" + }; + + + for (outptr = out; *in != '\0'; in ++) + { + /* + * Encode the up to 3 characters as 4 Base64 numbers... + */ + + *outptr ++ = base64[in[0] >> 2]; + *outptr ++ = base64[((in[0] << 4) | (in[1] >> 4)) & 63]; + + in ++; + if (*in == '\0') + break; + + *outptr ++ = base64[((in[0] << 2) | (in[1] >> 6)) & 63]; + + in ++; + if (*in == '\0') + break; + + *outptr ++ = base64[in[0] & 63]; + } + + *outptr ++ = '='; + *outptr = '\0'; + + /* + * Return the encoded string... + */ + + return (out); +} + + +/* + * 'httpGetLength()' - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + */ + +int /* O - Content length */ +httpGetLength(http_t *http) /* I - HTTP data */ +{ + if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0) + { + http->data_encoding = HTTP_ENCODE_CHUNKED; + http->data_remaining = 0; + } + else + { + http->data_encoding = HTTP_ENCODE_LENGTH; + + /* + * The following is a hack for HTTP servers that don't send a + * content-length or transfer-encoding field... + * + * If there is no content-length then the connection must close + * after the transfer is complete... + */ + + if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0') + http->data_remaining = 2147483647; + else + http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]); + } + + return (http->data_remaining); +} + + +/* + * 'http_field()' - Return the field index for a field name. + */ + +static http_field_t /* O - Field index */ +http_field(const char *name) /* I - String name */ +{ + int i; /* Looping var */ + + + for (i = 0; i < HTTP_FIELD_MAX; i ++) + if (strcasecmp(name, http_fields[i]) == 0) + return ((http_field_t)i); + + return (HTTP_FIELD_UNKNOWN); +} + + +/* + * 'http_send()' - Send a request with all fields and the trailing blank line. + */ + +static int /* O - 0 on success, non-zero on error */ +http_send(http_t *http, /* I - HTTP data */ + http_state_t request, /* I - Request code */ + const char *uri) /* I - URI */ +{ + int i; /* Looping var */ + char *ptr, /* Pointer in buffer */ + buf[1024]; /* Encoded URI buffer */ + static const char *codes[] = /* Request code strings */ + { + NULL, + "OPTIONS", + "GET", + NULL, + "HEAD", + "POST", + NULL, + NULL, + "PUT", + NULL, + "DELETE", + "TRACE", + "CLOSE" + }; + static const char *hex = "0123456789ABCDEF"; + /* Hex digits */ + + + if (http == NULL || uri == NULL) + return (-1); + + /* + * Encode the URI as needed... + */ + + for (ptr = buf; *uri != '\0'; uri ++) + if (*uri <= ' ' || *uri >= 127) + { + *ptr ++ = '%'; + *ptr ++ = hex[(*uri >> 4) & 15]; + *ptr ++ = hex[*uri & 15]; + } + else + *ptr ++ = *uri; + + *ptr = '\0'; + + /* + * Send the request header... + */ + + http->state = request; + if (request == HTTP_POST || request == HTTP_PUT) + http->state ++; + + http->status = HTTP_CONTINUE; + + if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1) + { + /* + * Might have lost connection; try to reconnect... + */ + + if (httpReconnect(http)) + return (-1); + + /* + * OK, we've reconnected, send the request again... + */ + + if (httpPrintf(http, "%s %s HTTP/%d.%d\r\n", codes[request], buf, + http->version / 100, http->version % 100) < 1) + return (-1); + } + + for (i = 0; i < HTTP_FIELD_MAX; i ++) + if (http->fields[i][0] != '\0') + { + DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i])); + + if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1) + return (-1); + } + + if (httpPrintf(http, "\r\n") < 1) + return (-1); + + httpClearFields(http); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/http.h b/cups/http.h new file mode 100644 index 0000000000..74c8938820 --- /dev/null +++ b/cups/http.h @@ -0,0 +1,293 @@ +/* + * "$Id$" + * + * Hyper-Text Transport Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_HTTP_H_ +# define _CUPS_HTTP_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# if defined(WIN32) || defined(__EMX__) +# include +# else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif /* WIN32 || __EMX__ */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Limits... + */ + +# define HTTP_MAX_URI 1024 /* Max length of URI string */ +# define HTTP_MAX_HOST 256 /* Max length of hostname string */ +# define HTTP_MAX_BUFFER 2048 /* Max length of data buffer */ +# define HTTP_MAX_VALUE 256 /* Max header field value length */ + + +/* + * HTTP state values... + */ + +typedef enum /* States are server-oriented */ +{ + HTTP_WAITING, /* Waiting for command */ + HTTP_OPTIONS, /* OPTIONS command, waiting for blank line */ + HTTP_GET, /* GET command, waiting for blank line */ + HTTP_GET_SEND, /* GET command, sending data */ + HTTP_HEAD, /* HEAD command, waiting for blank line */ + HTTP_POST, /* POST command, waiting for blank line */ + HTTP_POST_RECV, /* POST command, receiving data */ + HTTP_POST_SEND, /* POST command, sending data */ + HTTP_PUT, /* PUT command, waiting for blank line */ + HTTP_PUT_RECV, /* PUT command, receiving data */ + HTTP_DELETE, /* DELETE command, waiting for blank line */ + HTTP_TRACE, /* TRACE command, waiting for blank line */ + HTTP_CLOSE, /* CLOSE command, waiting for blank line */ + HTTP_STATUS /* Command complete, sending status */ +} http_state_t; + + +/* + * HTTP version numbers... + */ + +typedef enum +{ + HTTP_0_9 = 9, /* HTTP/0.9 */ + HTTP_1_0 = 100, /* HTTP/1.0 */ + HTTP_1_1 = 101 /* HTTP/1.1 */ +} http_version_t; + + +/* + * HTTP keep-alive values... + */ + +typedef enum +{ + HTTP_KEEPALIVE_OFF = 0, + HTTP_KEEPALIVE_ON +} http_keepalive_t; + + +/* + * HTTP transfer encoding values... + */ + +typedef enum +{ + HTTP_ENCODE_LENGTH, /* Data is sent with Content-Length */ + HTTP_ENCODE_CHUNKED /* Data is chunked */ +} http_encoding_t; + + +/* + * HTTP status codes... + */ + +typedef enum +{ + HTTP_ERROR = -1, /* An error response from httpXxxx() */ + + HTTP_CONTINUE = 100, /* Everything OK, keep going... */ + + HTTP_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */ + HTTP_CREATED, /* PUT command was successful */ + HTTP_ACCEPTED, /* DELETE command was successful */ + HTTP_NOT_AUTHORITATIVE, /* Information isn't authoritative */ + HTTP_NO_CONTENT, /* Successful command, no new data */ + HTTP_RESET_CONTENT, /* Content was reset/recreated */ + HTTP_PARTIAL_CONTENT, /* Only a partial file was recieved/sent */ + + HTTP_MULTIPLE_CHOICES = 300, /* Multiple files match request */ + HTTP_MOVED_PERMANENTLY, /* Document has moved permanently */ + HTTP_MOVED_TEMPORARILY, /* Document has moved temporarily */ + HTTP_SEE_OTHER, /* See this other link... */ + HTTP_NOT_MODIFIED, /* File not modified */ + HTTP_USE_PROXY, /* Must use a proxy to access this URI */ + + HTTP_BAD_REQUEST = 400, /* Bad request */ + HTTP_UNAUTHORIZED, /* Unauthorized to access host */ + HTTP_PAYMENT_REQUIRED, /* Payment required */ + HTTP_FORBIDDEN, /* Forbidden to access this URI */ + HTTP_NOT_FOUND, /* URI was not found */ + HTTP_METHOD_NOT_ALLOWED, /* Method is not allowed */ + HTTP_NOT_ACCEPTABLE, /* Not Acceptable */ + HTTP_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */ + HTTP_REQUEST_TIMEOUT, /* Request timed out */ + HTTP_CONFLICT, /* Request is self-conflicting */ + HTTP_GONE, /* Server has gone away */ + HTTP_LENGTH_REQUIRED, /* A content length or encoding is required */ + HTTP_PRECONDITION, /* Precondition failed */ + HTTP_REQUEST_TOO_LARGE, /* Request entity too large */ + HTTP_URI_TOO_LONG, /* URI too long */ + HTTP_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */ + + HTTP_SERVER_ERROR = 500, /* Internal server error */ + HTTP_NOT_IMPLEMENTED, /* Feature not implemented */ + HTTP_BAD_GATEWAY, /* Bad gateway */ + HTTP_SERVICE_UNAVAILABLE, /* Service is unavailable */ + HTTP_GATEWAY_TIMEOUT, /* Gateway connection timed out */ + HTTP_NOT_SUPPORTED /* HTTP version not supported */ +} http_status_t; + + +/* + * HTTP field names... + */ + +typedef enum +{ + HTTP_FIELD_UNKNOWN = -1, + HTTP_FIELD_ACCEPT_LANGUAGE, + HTTP_FIELD_ACCEPT_RANGES, + HTTP_FIELD_AUTHORIZATION, + HTTP_FIELD_CONNECTION, + HTTP_FIELD_CONTENT_ENCODING, + HTTP_FIELD_CONTENT_LANGUAGE, + HTTP_FIELD_CONTENT_LENGTH, + HTTP_FIELD_CONTENT_LOCATION, + HTTP_FIELD_CONTENT_MD5, + HTTP_FIELD_CONTENT_RANGE, + HTTP_FIELD_CONTENT_TYPE, + HTTP_FIELD_CONTENT_VERSION, + HTTP_FIELD_DATE, + HTTP_FIELD_HOST, + HTTP_FIELD_IF_MODIFIED_SINCE, + HTTP_FIELD_IF_UNMODIFIED_SINCE, + HTTP_FIELD_KEEP_ALIVE, + HTTP_FIELD_LAST_MODIFIED, + HTTP_FIELD_LINK, + HTTP_FIELD_LOCATION, + HTTP_FIELD_RANGE, + HTTP_FIELD_REFERER, + HTTP_FIELD_RETRY_AFTER, + HTTP_FIELD_TRANSFER_ENCODING, + HTTP_FIELD_UPGRADE, + HTTP_FIELD_USER_AGENT, + HTTP_FIELD_WWW_AUTHENTICATE, + HTTP_FIELD_MAX +} http_field_t; + + +/* + * HTTP connection structure... + */ + +typedef struct +{ + int fd; /* File descriptor for this socket */ + int blocking; /* To block or not to block */ + int error; /* Last error on read */ + time_t activity; /* Time since last read/write */ + http_state_t state; /* State of client */ + http_status_t status; /* Status of last request */ + http_version_t version; /* Protocol version */ + http_keepalive_t keep_alive; /* Keep-alive supported? */ + struct sockaddr_in hostaddr; /* Address of connected host */ + char hostname[HTTP_MAX_HOST], + /* Name of connected host */ + fields[HTTP_FIELD_MAX][HTTP_MAX_VALUE]; + /* Field values */ + char *data; /* Pointer to data buffer */ + http_encoding_t data_encoding; /* Chunked or not */ + int data_remaining; /* Number of bytes left */ + int used; /* Number of bytes used in buffer */ + char buffer[HTTP_MAX_BUFFER]; + /* Buffer for messages */ +} http_t; + + +/* + * Prototypes... + */ + +# define httpBlocking(http,b) (http)->blocking = (b) +extern int httpCheck(http_t *http); +# define httpClearFields(http) memset((http)->fields, 0, sizeof((http)->fields)),\ + httpSetField((http), HTTP_FIELD_HOST, (http)->hostname) +extern void httpClose(http_t *http); +extern http_t *httpConnect(const char *host, int port); +extern int httpDelete(http_t *http, const char *uri); +# define httpError(http) ((http)->error) +extern void httpFlush(http_t *http); +extern int httpGet(http_t *http, const char *uri); +extern char *httpGets(char *line, int length, http_t *http); +extern const char *httpGetDateString(time_t t); +extern time_t httpGetDateTime(const char *s); +# define httpGetField(http,field) (http)->fields[field] +extern int httpHead(http_t *http, const char *uri); +extern void httpInitialize(void); +extern int httpOptions(http_t *http, const char *uri); +extern int httpPost(http_t *http, const char *uri); +extern int httpPrintf(http_t *http, const char *format, ...); +extern int httpPut(http_t *http, const char *uri); +extern int httpRead(http_t *http, char *buffer, int length); +extern int httpReconnect(http_t *http); +extern void httpSeparate(const char *uri, char *method, char *username, + char *host, int *port, char *resource); +extern void httpSetField(http_t *http, http_field_t field, const char *value); +extern const char *httpStatus(http_status_t status); +extern int httpTrace(http_t *http, const char *uri); +extern http_status_t httpUpdate(http_t *http); +extern int httpWrite(http_t *http, const char *buffer, int length); +extern char *httpEncode64(char *out, const char *in); +extern char *httpDecode64(char *out, const char *in); +extern int httpGetLength(http_t *http); + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_HTTP_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/ipp.c b/cups/ipp.c new file mode 100644 index 0000000000..37aab1d981 --- /dev/null +++ b/cups/ipp.c @@ -0,0 +1,1459 @@ +/* + * "$Id$" + * + * Internet Printing Protocol support functions for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ippAddBoolean() - Add a boolean attribute to an IPP request. + * ippAddBooleans() - Add an array of boolean values. + * ippAddDate() - Add a date attribute to an IPP request. + * ippAddInteger() - Add a integer attribute to an IPP request. + * ippAddIntegers() - Add an array of integer values. + * ippAddString() - Add a language-encoded string to an IPP request. + * ippAddStrings() - Add language-encoded strings to an IPP request. + * ippAddRange() - Add a range of values to an IPP request. + * ippAddRanges() - Add ranges of values to an IPP request. + * ippAddResolution() - Add a resolution value to an IPP request. + * ippAddResolutions() - Add resolution values to an IPP request. + * ippAddSeparator() - Add a group separator to an IPP request. + * ippDateToTime() - Convert from RFC 1903 Date/Time format to UNIX time + * ippDelete() - Delete an IPP request. + * ippFindAttribute() - Find a named attribute in a request... + * ippLength() - Compute the length of an IPP request. + * ippPort() - Return the default IPP port number. + * ippRead() - Read data for an IPP request. + * ippTimeToDate() - Convert from UNIX time to RFC 1903 format. + * ippWrite() - Write data for an IPP request. + * add_attr() - Add a new attribute to the request. + * ipp_read() - Semi-blocking read on a HTTP connection... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#include "ipp.h" +#include "debug.h" + + +/* + * Local functions... + */ + +static ipp_attribute_t *add_attr(ipp_t *ipp, int num_values); +static int ipp_read(http_t *http, unsigned char *buffer, int length); + + +/* + * 'ippAddBoolean()' - Add a boolean attribute to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddBoolean(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + char value) /* I - Value of attribute */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddBoolean(%08x, %02x, \'%s\', %d)\n", ipp, group, name, value)); + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_BOOLEAN; + attr->values[0].boolean = value; + + return (attr); +} + + +/* + * 'ippAddBooleans()' - Add an array of boolean values. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddBooleans(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const char *values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddBooleans(%08x, %02x, \'%s\', %d, %08x)\n", ipp, + group, name, num_values, values)); + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_BOOLEAN; + + if (values != NULL) + for (i = 0; i < num_values; i ++) + attr->values[i].boolean = values[i]; + + return (attr); +} + + +/* + * 'ippAddDate()' - Add a date attribute to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddDate(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + const ipp_uchar_t *value) /* I - Value */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddDate(%08x, %02x, \'%s\', %08x)\n", ipp, group, name, + value)); + + if (ipp == NULL || name == NULL || value == NULL) + return (NULL); + + if ((attr = add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_DATE; + memcpy(attr->values[0].date, value, 11); + + return (attr); +} + + +/* + * 'ippAddInteger()' - Add a integer attribute to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddInteger(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + int value) /* I - Value of attribute */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddInteger(%08x, %d, \'%s\', %d)\n", ipp, group, name, + value)); + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + attr->values[0].integer = value; + + return (attr); +} + + +/* + * 'ippAddIntegers()' - Add an array of integer values. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddIntegers(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const int *values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + + if (values != NULL) + for (i = 0; i < num_values; i ++) + attr->values[i].integer = values[i]; + + return (attr); +} + + +/* + * 'ippAddString()' - Add a language-encoded string to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddString(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + const char *charset, /* I - Character set */ + const char *value) /* I - Value */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + attr->values[0].string.charset = charset ? strdup(charset) : NULL; + attr->values[0].string.text = strdup(value); + + return (attr); +} + + +/* + * 'ippAddStrings()' - Add language-encoded strings to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddStrings(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + ipp_tag_t type, /* I - Type of attribute */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const char *charset, /* I - Character set */ + const char **values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = type; + + if (values != NULL) + for (i = 0; i < num_values; i ++) + { + if (i == 0) + attr->values[0].string.charset = charset ? strdup(charset) : NULL; + else + attr->values[i].string.charset = attr->values[0].string.charset; + + attr->values[i].string.text = strdup(values[i]); + } + + return (attr); +} + + +/* + * 'ippAddRange()' - Add a range of values to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddRange(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int lower, /* I - Lower value */ + int upper) /* I - Upper value */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RANGE; + attr->values[0].range.lower = lower; + attr->values[0].range.upper = upper; + + return (attr); +} + + +/* + * 'ippAddRanges()' - Add ranges of values to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddRanges(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const int *lower, /* I - Lower values */ + const int *upper) /* I - Upper values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RANGE; + + if (lower != NULL && upper != NULL) + for (i = 0; i < num_values; i ++) + { + attr->values[i].range.lower = lower[i]; + attr->values[i].range.upper = upper[i]; + } + + return (attr); +} + + +/* + * 'ippAddResolution()' - Add a resolution value to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddResolution(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + ipp_res_t units, /* I - Units for resolution */ + int xres, /* I - X resolution */ + int yres) /* I - Y resolution */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, 1)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RESOLUTION; + attr->values[0].resolution.xres = xres; + attr->values[0].resolution.yres = yres; + attr->values[0].resolution.units = units; + + return (attr); +} + + +/* + * 'ippAddResolutions()' - Add resolution values to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddResolutions(ipp_t *ipp, /* I - IPP request */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int num_values,/* I - Number of values */ + ipp_res_t units, /* I - Units for resolution */ + const int *xres, /* I - X resolutions */ + const int *yres) /* I - Y resolutions */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = add_attr(ipp, num_values)) == NULL) + return (NULL); + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_RESOLUTION; + + if (xres != NULL && yres != NULL) + for (i = 0; i < num_values; i ++) + { + attr->values[i].resolution.xres = xres[i]; + attr->values[i].resolution.yres = yres[i]; + attr->values[i].resolution.units = units; + } + + return (attr); +} + + +/* + * 'ippAddSeparator()' - Add a group separator to an IPP request. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddSeparator(ipp_t *ipp) /* I - IPP request */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddSeparator(%08x)\n", ipp)); + + if (ipp == NULL) + return (NULL); + + if ((attr = add_attr(ipp, 0)) == NULL) + return (NULL); + + attr->group_tag = IPP_TAG_ZERO; + attr->value_tag = IPP_TAG_ZERO; + + return (attr); +} + + +/* + * 'ippDateToTime()' - Convert from RFC 1903 Date/Time format to UNIX time + * in seconds. + */ + +time_t /* O - UNIX time value */ +ippDateToTime(const ipp_uchar_t *date) /* I - RFC 1903 date info */ +{ + struct tm unixdate; /* UNIX date/time info */ + time_t t; /* Computed time */ + + + memset(&unixdate, 0, sizeof(unixdate)); + + /* + * RFC-1903 date/time format is: + * + * Byte(s) Description + * ------- ----------- + * 0-1 Year (0 to 65535) + * 2 Month (1 to 12) + * 3 Day (1 to 31) + * 4 Hours (0 to 23) + * 5 Minutes (0 to 59) + * 6 Seconds (0 to 60, 60 = "leap second") + * 7 Deciseconds (0 to 9) + * 8 +/- UTC + * 9 UTC hours (0 to 11) + * 10 UTC minutes (0 to 59) + */ + + unixdate.tm_year = ((date[0] << 8) | date[1]) - 1900; + unixdate.tm_mon = date[2] - 1; + unixdate.tm_mday = date[3]; + unixdate.tm_hour = date[4]; + unixdate.tm_min = date[5]; + unixdate.tm_sec = date[6]; + + t = mktime(&unixdate); + + if (date[8] == '-') + t += date[9] * 3600 + date[10] * 60; + else + t -= date[9] * 3600 + date[10] * 60; + + t -= timezone; + + return (t); +} + + +/* + * 'ippDelete()' - Delete an IPP request. + */ + +void +ippDelete(ipp_t *ipp) /* I - IPP request */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr, /* Current attribute */ + *next; /* Next attribute */ + + + if (ipp == NULL) + return; + + for (attr = ipp->attrs; attr != NULL; attr = next) + { + switch (attr->value_tag) + { + 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 ++) + free(attr->values[i].string.text); + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + for (i = 0; i < attr->num_values; i ++) + { + if (attr->values[i].string.charset) + free(attr->values[i].string.charset); + free(attr->values[i].string.text); + } + break; + } + + next = attr->next; + + if (attr->name != NULL) + free(attr->name); + + free(attr); + } + + free(ipp); +} + + +/* + * 'ippFindAttribute()' - Find a named attribute in a request... + */ + +ipp_attribute_t * /* O - Matching attribute */ +ippFindAttribute(ipp_t *ipp, /* I - IPP request */ + const char *name, /* I - Name of attribute */ + ipp_tag_t type) /* I - Type of attribute */ +{ + ipp_attribute_t *attr; /* Current atttribute */ + + + DEBUG_printf(("ippFindAttribute(%08x, \'%s\')\n", ipp, name)); + + if (ipp == NULL || name == NULL) + return (NULL); + + for (attr = ipp->attrs; attr != NULL; attr = attr->next) + { + DEBUG_printf(("ippFindAttribute: attr = %08x, name = \'%s\'\n", attr, + attr->name)); + + if (attr->name != NULL && strcmp(attr->name, name) == 0 && + (attr->value_tag == type || + (attr->value_tag == IPP_TAG_TEXTLANG && type == IPP_TAG_TEXT) || + (attr->value_tag == IPP_TAG_NAMELANG && type == IPP_TAG_NAME))) + return (attr); + } + + return (NULL); +} + + +/* + * 'ippLength()' - Compute the length of an IPP request. + */ + +size_t /* O - Size of IPP request */ +ippLength(ipp_t *ipp) /* I - IPP request */ +{ + int i; /* Looping var */ + int bytes; /* Number of bytes */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_tag_t group; /* Current group */ + + + if (ipp == NULL) + return (0); + + /* + * Start with 8 bytes for the IPP request or status header... + */ + + bytes = 8; + + /* + * Then add the lengths of each attribute... + */ + + group = IPP_TAG_ZERO; + + for (attr = ipp->attrs; attr != NULL; attr = attr->next) + { + if (attr->group_tag != group) + { + group = attr->group_tag; + if (group == IPP_TAG_ZERO) + continue; + + bytes ++; /* Group tag */ + } + + DEBUG_printf(("attr->name = %s, attr->num_values = %d, bytes = %d\n", + attr->name, attr->num_values, bytes)); + + bytes += strlen(attr->name); /* Name */ + bytes += attr->num_values; /* Value tag for each value */ + bytes += 2 * attr->num_values; /* Name lengths */ + bytes += 2 * attr->num_values; /* Value lengths */ + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + bytes += 4 * attr->num_values; + break; + + case IPP_TAG_BOOLEAN : + bytes += attr->num_values; + 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 ++) + bytes += strlen(attr->values[i].string.text); + break; + + case IPP_TAG_DATE : + bytes += 11 * attr->num_values; + break; + + case IPP_TAG_RESOLUTION : + bytes += 9 * attr->num_values; + break; + + case IPP_TAG_RANGE : + bytes += 8 * attr->num_values; + break; + + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + bytes += 2 * attr->num_values;/* Charset length */ + for (i = 0; i < attr->num_values; i ++) + bytes += strlen(attr->values[i].string.charset) + + strlen(attr->values[i].string.text); + break; + } + } + + /* + * Finally, add 1 byte for the "end of attributes" tag and return... + */ + + DEBUG_printf(("bytes = %d\n", bytes + 1)); + + return (bytes + 1); +} + + +ipp_t * /* O - New IPP request */ +ippNew(void) +{ + return ((ipp_t *)calloc(sizeof(ipp_t), 1)); +} + + +/* + * 'ippRead()' - Read data for an IPP request. + */ + +ipp_state_t /* O - Current state */ +ippRead(http_t *http, /* I - HTTP data */ + ipp_t *ipp) /* I - IPP data */ +{ + int n; /* Length of data */ + unsigned char buffer[8192]; /* Data buffer */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_tag_t tag; /* Current tag */ + + + DEBUG_printf(("ippRead(%08x, %08x)\n", http, ipp)); + + if (http == NULL || ipp == NULL) + return (IPP_ERROR); + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + /* + * Get the request header... + */ + + if ((n = ipp_read(http, buffer, 8)) < 8) + { + DEBUG_printf(("ippRead: Unable to read header (%d bytes read)!\n", n)); + return (n == 0 ? IPP_IDLE : IPP_ERROR); + } + + /* + * Verify the major version number... + */ + + if (buffer[0] != 1) + { + DEBUG_printf(("ippRead: version number (%d.%d) is bad.\n", buffer[0], + buffer[1])); + 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; + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking && http->used == 0) + break; + + case IPP_ATTRIBUTE : + while (ipp_read(http, buffer, 1) > 0) + { + /* + * Read this attribute... + */ + + tag = (ipp_tag_t)buffer[0]; + + if (tag == IPP_TAG_END) + { + /* + * No more attributes left... + */ + + DEBUG_puts("ippRead: IPP_TAG_END!"); + + ipp->state = IPP_DATA; + break; + } + else if (tag <= IPP_TAG_UNSUPPORTED) + { + /* + * Group tag... Set the current group and continue... + */ + + if (ipp->curtag == tag) + ippAddSeparator(ipp); + + ipp->curtag = tag; + ipp->current = NULL; + DEBUG_printf(("ippRead: group tag = %x\n", tag)); + continue; + } + + DEBUG_printf(("ippRead: value tag = %x\n", tag)); + + /* + * Get the name... + */ + + if (ipp_read(http, buffer, 2) < 2) + { + DEBUG_puts("ippRead: unable to read name length!"); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + + DEBUG_printf(("ippRead: name length = %d\n", n)); + + if (n == 0) + { + /* + * More values for current attribute... + */ + + if (ipp->current == NULL) + return (IPP_ERROR); + + attr = ipp->current; + + if (attr->num_values >= IPP_MAX_VALUES) + return (IPP_ERROR); + } + else + { + /* + * New attribute; read the name and add it... + */ + + if (ipp_read(http, buffer, n) < n) + { + DEBUG_puts("ippRead: unable to read name!"); + return (IPP_ERROR); + } + + buffer[n] = '\0'; + DEBUG_printf(("ippRead: name = \'%s\'\n", buffer)); + + attr = ipp->current = 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 (ipp_read(http, buffer, 2) < 2) + { + DEBUG_puts("ippRead: unable to read value length!"); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + DEBUG_printf(("ippRead: value length = %d\n", n)); + + switch (tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if (ipp_read(http, buffer, 4) < 4) + 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 (ipp_read(http, buffer, 1) < 1) + 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 (ipp_read(http, buffer, n) < n) + return (IPP_ERROR); + + buffer[n] = '\0'; + DEBUG_printf(("ippRead: value = \'%s\'\n", buffer)); + + attr->values[attr->num_values].string.text = strdup((char *)buffer); + break; + case IPP_TAG_DATE : + if (ipp_read(http, buffer, 11) < 11) + return (IPP_ERROR); + + memcpy(attr->values[attr->num_values].date, buffer, 11); + break; + case IPP_TAG_RESOLUTION : + if (ipp_read(http, buffer, 9) < 9) + 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 (ipp_read(http, buffer, 8) < 8) + 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 (ipp_read(http, buffer, n) < n) + return (IPP_ERROR); + + buffer[n] = '\0'; + + attr->values[attr->num_values].string.charset = strdup((char *)buffer); + + if (ipp_read(http, buffer, 2) < 2) + return (IPP_ERROR); + + n = (buffer[0] << 8) | buffer[1]; + + if (ipp_read(http, buffer, n) < n) + return (IPP_ERROR); + + buffer[n] = '\0'; + + attr->values[attr->num_values].string.text = strdup((char *)buffer); + break; + } + + attr->num_values ++; + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking && http->used == 0) + break; + } + break; + + case IPP_DATA : + break; + } + + return (ipp->state); +} + + +/* + * 'ippTimeToDate()' - Convert from UNIX time to RFC 1903 format. + */ + +const ipp_uchar_t * /* O - RFC-1903 date/time data */ +ippTimeToDate(time_t t) /* I - UNIX time value */ +{ + struct tm *unixdate; /* UNIX unixdate/time info */ + static ipp_uchar_t date[11]; /* RFC-1903 date/time data */ + + + /* + * RFC-1903 date/time format is: + * + * Byte(s) Description + * ------- ----------- + * 0-1 Year (0 to 65535) + * 2 Month (1 to 12) + * 3 Day (1 to 31) + * 4 Hours (0 to 23) + * 5 Minutes (0 to 59) + * 6 Seconds (0 to 60, 60 = "leap second") + * 7 Deciseconds (0 to 9) + * 8 +/- UTC + * 9 UTC hours (0 to 11) + * 10 UTC minutes (0 to 59) + */ + + unixdate = gmtime(&t); + unixdate->tm_year += 1900; + + date[0] = unixdate->tm_year >> 8; + date[1] = unixdate->tm_year; + date[2] = unixdate->tm_mon + 1; + date[3] = unixdate->tm_mday; + date[4] = unixdate->tm_hour; + date[5] = unixdate->tm_min; + date[6] = unixdate->tm_sec; + date[7] = 0; + date[8] = '+'; + date[9] = 0; + date[10] = 0; + + return (date); +} + + +/* + * 'ippWrite()' - Write data for an IPP request. + */ + +ipp_state_t /* O - Current state */ +ippWrite(http_t *http, /* I - HTTP data */ + ipp_t *ipp) /* I - IPP data */ +{ + 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 */ + + + if (http == NULL || ipp == NULL) + return (IPP_ERROR); + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + /* + * Send the request header... + */ + + bufptr = buffer; + + *bufptr++ = 1; + *bufptr++ = 0; + *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 (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP header..."); + return (IPP_ERROR); + } + + ipp->state = IPP_ATTRIBUTE; + ipp->current = ipp->attrs; + ipp->curtag = IPP_TAG_ZERO; + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking) + break; + + 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(("ippWrite: wrote group tag = %x\n", attr->group_tag)); + *bufptr++ = attr->group_tag; + } + + n = strlen(attr->name); + + DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag)); + DEBUG_printf(("ippWrite: 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 (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 (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(("ippWrite: writing value tag = %x\n", + attr->value_tag)); + DEBUG_printf(("ippWrite: writing name = 0, \'\'\n")); + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = strlen(attr->values[i].string.text); + + DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n, + attr->values[i].string.text)); + + *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 (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 (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 (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... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = strlen(attr->values[i].string.charset); + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->values[i].string.charset, n); + bufptr += n; + + n = strlen(attr->values[i].string.text); + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->values[i].string.text, n); + bufptr += n; + } + break; + } + + /* + * Write the data out... + */ + + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + DEBUG_printf(("ippWrite: wrote %d bytes\n", bufptr - buffer)); + + /* + * If blocking is disabled, stop here... + */ + + if (!http->blocking) + break; + } + + if (ipp->current == NULL) + { + /* + * Done with all of the attributes; add the end-of-attributes tag... + */ + + buffer[0] = IPP_TAG_END; + if (httpWrite(http, (char *)buffer, 1) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP end-tag..."); + return (IPP_ERROR); + } + + ipp->state = IPP_DATA; + } + break; + + case IPP_DATA : + break; + } + + return (ipp->state); +} + + +/* + * 'ippPort()' - Return the default IPP port number. + */ + +int /* O - Port number */ +ippPort(void) +{ + const char *server_port; /* SERVER_PORT environment variable */ + struct servent *port; /* Port number info */ + + + if ((server_port = getenv("IPP_PORT")) != NULL) + return (atoi(server_port)); + else if ((port = getservbyname("ipp", NULL)) == NULL) + return (IPP_PORT); + else + return (ntohs(port->s_port)); +} + + +/* + * 'add_attr()' - Add a new attribute to the request. + */ + +static ipp_attribute_t * /* O - New attribute */ +add_attr(ipp_t *ipp, /* I - IPP request */ + int num_values) /* I - Number of values */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("add_attr(%08x, %d)\n", ipp, num_values)); + + if (ipp == NULL || num_values < 0) + return (NULL); + + attr = calloc(sizeof(ipp_attribute_t) + + (num_values - 1) * sizeof(ipp_value_t), 1); + + attr->num_values = num_values; + + if (attr == NULL) + return (NULL); + + if (ipp->last == NULL) + ipp->attrs = attr; + else + ipp->last->next = attr; + + ipp->last = attr; + + return (attr); +} + + +/* + * 'ipp_read()' - Semi-blocking read on a HTTP connection... + */ + +static int /* O - Number of bytes read */ +ipp_read(http_t *http, /* I - Client connection */ + unsigned char *buffer, /* O - Buffer for data */ + int length) /* I - Total length */ +{ + int tbytes, /* Total bytes read */ + bytes; /* Bytes read this pass */ + + + /* + * Loop until all bytes are read... + */ + + for (tbytes = 0; tbytes < length; tbytes += bytes, buffer += bytes) + if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0) + break; + + /* + * Return the number of bytes read... + */ + + return (tbytes); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/ipp.h b/cups/ipp.h new file mode 100644 index 0000000000..0b343f5610 --- /dev/null +++ b/cups/ipp.h @@ -0,0 +1,343 @@ +/* + * "$Id$" + * + * Internet Printing Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_IPP_H_ +# define _CUPS_IPP_H_ + +/* + * Include necessary headers... + */ + +# include + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * IPP version string... + */ + +# define IPP_VERSION "\001\000" + +/* + * IPP registered port number... This is the default value - applications + * should use the ippPort() function so that you can customize things in + * /etc/services if needed! + */ + +# define IPP_PORT 631 + +/* + * Common limits... + */ + +# define IPP_MAX_NAME 256 +# define IPP_MAX_VALUES 100 + + +/* + * Types and structures... + */ + +typedef enum /**** Format tags for attribute formats... ****/ +{ + IPP_TAG_ZERO = 0x00, + IPP_TAG_OPERATION, + IPP_TAG_JOB, + IPP_TAG_END, + IPP_TAG_PRINTER, + IPP_TAG_EXTENSION, + IPP_TAG_UNSUPPORTED = 0x10, + IPP_TAG_DEFAULT, + IPP_TAG_UNKNOWN, + IPP_TAG_NOVALUE, + IPP_TAG_INTEGER = 0x21, + IPP_TAG_BOOLEAN, + IPP_TAG_ENUM, + IPP_TAG_STRING = 0x30, + IPP_TAG_DATE, + IPP_TAG_RESOLUTION, + IPP_TAG_RANGE, + IPP_TAG_COLLECTION, + IPP_TAG_TEXTLANG, + IPP_TAG_NAMELANG, + IPP_TAG_TEXT = 0x41, + IPP_TAG_NAME, + IPP_TAG_KEYWORD = 0x44, + IPP_TAG_URI, + IPP_TAG_URISCHEME, + IPP_TAG_CHARSET, + IPP_TAG_LANGUAGE, + IPP_TAG_MIMETYPE +} ipp_tag_t; + +typedef enum /**** Resolution units... ****/ +{ + IPP_RES_PER_INCH = 3, + IPP_RES_PER_CM +} ipp_res_t; + +typedef enum /**** Multiple Document Handling ****/ +{ + IPP_DOC_SINGLE, + IPP_DOC_UNCOLLATED, + IPP_DOC_COLLATED, + IPP_DOC_SEPARATE +} ipp_doc_t; + +typedef enum /**** Finishings... ****/ +{ + IPP_FINISH_NONE = 3, + IPP_FINISH_STAPLE, + IPP_FINISH_PUNCH, + IPP_FINISH_COVER, + IPP_FINISH_BIND +} ipp_finish_t; + +typedef enum /**** Orientation... ****/ +{ + IPP_PORTRAIT = 3, /* No rotation */ + IPP_LANDSCAPE, /* 90 degrees counter-clockwise */ + IPP_REVERSE_LANDSCAPE, /* 90 degrees clockwise */ + IPP_REVERSE_PORTRAIT /* 180 degrees */ +} ipp_orient_t; + +typedef enum /**** Qualities... ****/ +{ + IPP_QUALITY_DRAFT = 3, + IPP_QUALITY_NORMAL, + IPP_QUALITY_HIGH +} ipp_quality_t; + +typedef enum /**** Job States.... */ +{ + IPP_JOB_PENDING = 3, + IPP_JOB_HELD, + IPP_JOB_PROCESSING, + IPP_JOB_STOPPED, + IPP_JOB_CANCELED, + IPP_JOB_ABORTED, + IPP_JOB_COMPLETED +} ipp_jstate_t; + +typedef enum /**** Printer States.... */ +{ + IPP_PRINTER_IDLE = 3, + IPP_PRINTER_PROCESSING, + IPP_PRINTER_STOPPED +} ipp_pstate_t; + +typedef enum /**** IPP states... ****/ +{ + IPP_ERROR = -1, /* An error occurred */ + IPP_IDLE, /* Nothing is happening/request completed */ + IPP_HEADER, /* The request header needs to be sent/received */ + IPP_ATTRIBUTE, /* One or more attributes need to be sent/received */ + IPP_DATA /* IPP request data needs to be sent/received */ +} ipp_state_t; + +typedef enum /**** IPP operations... ****/ +{ + IPP_PRINT_JOB = 0x0002, + IPP_PRINT_URI, + IPP_VALIDATE_JOB, + IPP_CREATE_JOB, + IPP_SEND_DOCUMENT, + IPP_SEND_URI, + IPP_CANCEL_JOB, + IPP_GET_JOB_ATTRIBUTES, + IPP_GET_JOBS, + IPP_GET_PRINTER_ATTRIBUTES, + IPP_HOLD_JOB = 0x000c, + IPP_RELEASE_JOB, + IPP_RESTART_JOB, + IPP_PAUSE_PRINTER = 0x0010, + IPP_RESUME_PRINTER, + IPP_PURGE_JOBS, + IPP_PRIVATE = 0x4000, + CUPS_GET_DEFAULT, + CUPS_GET_PRINTERS, + CUPS_ADD_PRINTER, + CUPS_DELETE_PRINTER, + CUPS_GET_CLASSES, + CUPS_ADD_CLASS, + CUPS_DELETE_CLASS, + CUPS_ACCEPT_JOBS, + CUPS_REJECT_JOBS, + CUPS_SET_DEFAULT +} ipp_op_t; + +typedef enum /**** IPP status codes... ****/ +{ + IPP_OK = 0x0000, + IPP_OK_SUBST, + IPP_OK_CONFLICT, + IPP_BAD_REQUEST = 0x0400, + IPP_FORBIDDEN, + IPP_NOT_AUTHENTICATED, + IPP_NOT_AUTHORIZED, + IPP_NOT_POSSIBLE, + IPP_TIMEOUT, + IPP_NOT_FOUND, + IPP_GONE, + IPP_REQUEST_ENTITY, + IPP_REQUEST_VALUE, + IPP_DOCUMENT_FORMAT, + IPP_ATTRIBUTES, + IPP_URI_SCHEME, + IPP_CHARSET, + IPP_CONFLICT, + IPP_INTERNAL_ERROR = 0x0500, + IPP_OPERATION_NOT_SUPPORTED, + IPP_SERVICE_UNAVAILABLE, + IPP_VERSION_NOT_SUPPORTED, + IPP_DEVICE_UNAVAILABLE, + IPP_TEMPORARY_ERROR, + IPP_NOT_ACCEPTING, + IPP_PRINTER_BUSY +} ipp_status_t; + +typedef unsigned char ipp_uchar_t;/**** Unsigned 8-bit integer/character ****/ + +typedef union /**** Request Header ****/ +{ + struct /* Any Header */ + { + ipp_uchar_t version[2]; /* Protocol version number */ + int op_status; /* Operation ID or status code*/ + int request_id; /* Request ID */ + } any; + + struct /* Operation Header */ + { + ipp_uchar_t version[2]; /* Protocol version number */ + ipp_op_t operation_id; /* Operation ID */ + int request_id; /* Request ID */ + } op; + + struct /* Status Header */ + { + ipp_uchar_t version[2]; /* Protocol version number */ + ipp_status_t status_code; /* Status code */ + int request_id; /* Request ID */ + } status; +} ipp_request_t; + + +typedef union /**** Attribute Value ****/ +{ + int integer; /* Integer/enumerated value */ + + char boolean; /* Boolean value */ + + ipp_uchar_t date[11]; /* Date/time value */ + + struct + { + int xres, /* Horizontal resolution */ + yres; /* Vertical resolution */ + ipp_res_t units; /* Resolution units */ + } resolution; /* Resolution value */ + + struct + { + int lower, /* Lower value */ + upper; /* Upper value */ + } range; /* Range of integers value */ + + struct + { + char *charset; /* Character set */ + char *text; /* String */ + } string; /* String with language value */ +} ipp_value_t; + +typedef struct ipp_attribute_s /**** Attribute ****/ +{ + struct ipp_attribute_s *next; + /* Next atrtribute in list */ + ipp_tag_t group_tag, /* Job/Printer/Operation group tag */ + value_tag; /* What type of value is it? */ + char *name; /* Name of attribute */ + int num_values; /* Number of values */ + ipp_value_t values[1]; /* Values */ +} ipp_attribute_t; + +typedef struct /**** Request State ****/ +{ + ipp_state_t state; /* State of request */ + ipp_request_t request; /* Request header */ + ipp_attribute_t *attrs, /* Attributes */ + *last, /* Last attribute in list */ + *current; /* Current attribute (for read/write) */ + ipp_tag_t curtag; /* Current attribute group tag */ +} ipp_t; + + +/* + * Prototypes... + */ + +extern time_t ippDateToTime(const ipp_uchar_t *date); +extern ipp_attribute_t *ippAddBoolean(ipp_t *ipp, ipp_tag_t group, const char *name, char value); +extern ipp_attribute_t *ippAddBooleans(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const char *values); +extern ipp_attribute_t *ippAddDate(ipp_t *ipp, ipp_tag_t group, const char *name, const ipp_uchar_t *value); +extern ipp_attribute_t *ippAddInteger(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, int value); +extern ipp_attribute_t *ippAddIntegers(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, int num_values, const int *values); +extern ipp_attribute_t *ippAddRange(ipp_t *ipp, ipp_tag_t group, const char *name, int lower, int upper); +extern ipp_attribute_t *ippAddRanges(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const int *lower, const int *upper); +extern ipp_attribute_t *ippAddResolution(ipp_t *ipp, ipp_tag_t group, const char *name, ipp_res_t units, int xres, int yres); +extern ipp_attribute_t *ippAddResolutions(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, ipp_res_t units, const int *xres, const int *yres); +extern ipp_attribute_t *ippAddSeparator(ipp_t *ipp); +extern ipp_attribute_t *ippAddString(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, const char *charset, const char *value); +extern ipp_attribute_t *ippAddStrings(ipp_t *ipp, ipp_tag_t group, ipp_tag_t type, const char *name, int num_values, const char *charset, const char **values); +extern void ippDelete(ipp_t *ipp); +extern ipp_attribute_t *ippFindAttribute(ipp_t *ipp, const char *name, ipp_tag_t type); +extern size_t ippLength(ipp_t *ipp); +extern ipp_t *ippNew(void); +extern ipp_state_t ippRead(http_t *http, ipp_t *ipp); +extern const ipp_uchar_t *ippTimeToDate(time_t t); +extern ipp_state_t ippWrite(http_t *http, ipp_t *ipp); +extern int ippPort(void); + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_IPP_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/language.c b/cups/language.c new file mode 100644 index 0000000000..4e015e4298 --- /dev/null +++ b/cups/language.c @@ -0,0 +1,374 @@ +/* + * "$Id$" + * + * I18N/language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsLangEncoding() - Return the character encoding (us-ascii, etc.) + * for the given language. + * cupsLangFlush() - Flush all language data out of the cache. + * cupsLangFree() - Free language data. + * cupsLangGet() - Get a language. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include "string.h" +#include "language.h" + + +/* + * Local globals... + */ + +static cups_lang_t *lang_cache = NULL; /* Language string cache */ +static char *lang_blank = ""; /* Blank constant string */ +static char *lang_encodings[] = /* Encoding strings */ + { + "us-ascii", + "iso8859-1", + "iso8859-2", + "iso8859-3", + "iso8859-4", + "iso8859-5", + "iso8859-6", + "iso8859-7", + "iso8859-8", + "iso8859-9", + "iso8859-10", + "utf8" + }; +static char *lang_default[] = /* Default POSIX locale */ + { +#include "cups_C.h" + NULL + }; + + +/* + * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.) + * for the given language. + */ + +char * /* O - Character encoding */ +cupsLangEncoding(cups_lang_t *lang) /* I - Language data */ +{ + if (lang == NULL) + return (lang_encodings[0]); + else + return (lang_encodings[lang->encoding]); +} + + +/* + * 'cupsLangFlush()' - Flush all language data out of the cache. + */ + +void +cupsLangFlush(void) +{ + int i; /* Looping var */ + cups_lang_t *lang, /* Current language */ + *next; /* Next language */ + + + for (lang = lang_cache; lang != NULL; lang = next) + { + for (i = 0; i < CUPS_MSG_MAX; i ++) + if (lang->messages[i] != NULL && lang->messages[i] != lang_blank) + free(lang->messages[i]); + + next = lang->next; + free(lang); + } +} + + +/* + * 'cupsLangFree()' - Free language data. + * + * This does not actually free anything; use cupsLangFlush() for that. + */ + +void +cupsLangFree(cups_lang_t *lang) /* I - Language to free */ +{ + if (lang != NULL && lang->used > 0) + lang->used --; +} + + +/* + * 'cupsLangGet()' - Get a language. + */ + +cups_lang_t * /* O - Language data */ +cupsLangGet(const char *language) /* I - Language or locale */ +{ + int i, count; /* Looping vars */ + char langname[16], /* Requested language name */ + real[16], /* Real language name */ + filename[1024], /* Filename for language locale file */ + *localedir; /* Directory for locale files */ + FILE *fp; /* Language locale file pointer */ + char line[1024]; /* Line from file */ + cups_msg_t msg; /* Message number */ + char *text; /* Message text */ + cups_lang_t *lang; /* Current language... */ + + + /* + * Convert the language string passed in to a locale string. "C" is the + * standard POSIX locale and is copied unchanged. Otherwise the + * language string is converted from ll-cc (language-country) to ll_CC + * to match the file naming convention used by all POSIX-compliant + * operating systems. + */ + + if (language == NULL || language[0] == '\0' || + strcmp(language, "POSIX") == 0) + strcpy(langname, "C"); + else + strcpy(langname, language); + + if (strlen(langname) < 2) + strcpy(real, "C"); + else + { + real[0] = tolower(langname[0]); + real[1] = tolower(langname[1]); + + if (langname[2] == '_' || langname[2] == '-') + { + real[2] = '_'; + real[3] = toupper(langname[3]); + real[4] = toupper(langname[4]); + real[5] = '\0'; + langname[5] = '\0'; + } + else + { + langname[2] = '\0'; + real[2] = '\0'; + } + } + + /* + * Next try to open a locale file; we will try the country-localized file + * first, and then look for generic language file. If all else fails we + * will use the POSIX locale. + */ + + if ((localedir = getenv("LOCALEDIR")) == NULL) + localedir = CUPS_LOCALEDIR; + + sprintf(filename, "%s/%s/cups_%s", localedir, real, real); + + if ((fp = fopen(filename, "r")) == NULL) + if (strlen(real) > 2) + { + /* + * Nope, see if we can open a generic language file... + */ + + real[2] = '\0'; + sprintf(filename, "%s/%s/cups_%s", localedir, real, real); + fp = fopen(filename, "r"); + } + + /* + * Then see if we already have this language loaded... + */ + + for (lang = lang_cache; lang != NULL; lang = lang->next) + if (strcmp(lang->language, langname) == 0) + { + lang->used ++; + + if (fp != NULL) + fclose(fp); + + return (lang); + } + + /* + * OK, we have an open messages file; the first line will contain the + * language encoding (us-ascii, iso-8859-1, etc.), and the rest will + * be messages consisting of: + * + * #### SP message text + * + * or: + * + * message text + * + * If the line starts with a number, then message processing picks up + * where the number indicates. Otherwise the last message number is + * incremented. + * + * All leading whitespace is deleted. + */ + + if (fp == NULL) + strcpy(line, lang_default[0]); + else if (fgets(line, sizeof(line), fp) == NULL) + { + /* + * Can't read encoding! + */ + + fclose(fp); + return (NULL); + } + + i = strlen(line) - 1; + if (line[i] == '\n') + line[i] = '\0'; /* Strip LF */ + + /* + * See if there is a free language available; if so, use that + * record... + */ + + for (lang = lang_cache; lang != NULL; lang = lang->next) + if (lang->used == 0) + break; + + if (lang == NULL) + { + /* + * Allocate memory for the language and add it to the cache. + */ + + if ((lang = calloc(sizeof(cups_lang_t), 1)) == NULL) + { + fclose(fp); + return (NULL); + } + + lang->next = lang_cache; + lang_cache = lang; + } + + + /* + * Free all old strings as needed... + */ + + for (i = 0; i < CUPS_MSG_MAX; i ++) + { + if (lang->messages[i] != NULL && lang->messages[i] != lang_blank) + free(lang->messages[i]); + + lang->messages[i] = lang_blank; + } + + /* + * Then assign the language and encoding fields... + */ + + lang->used ++; + strcpy(lang->language, langname); + + for (i = 0; i < (sizeof(lang_encodings) / sizeof(lang_encodings[0])); i ++) + if (strcmp(lang_encodings[i], line) == 0) + { + lang->encoding = (cups_encoding_t)i; + break; + } + + /* + * Read the strings from the file... + */ + + msg = (cups_msg_t)-1; + count = 1; + + for (;;) + { + /* + * Read a line from memory or from a file... + */ + + if (fp == NULL) + { + if (lang_default[count] == NULL) + break; + + strcpy(line, lang_default[count]); + } + else if (fgets(line, sizeof(line), fp) == NULL) + break; + + count ++; + + /* + * Ignore blank lines... + */ + + i = strlen(line) - 1; + if (line[i] == '\n') + line[i] = '\0'; /* Strip LF */ + + if (line[0] == '\0') + continue; + + /* + * Grab the message number and text... + */ + + if (isdigit(line[0])) + msg = (cups_msg_t)atoi(line); + else + msg ++; + + if (msg < 0 || msg >= CUPS_MSG_MAX) + continue; + + text = line; + while (isdigit(*text)) + text ++; + while (isspace(*text)) + text ++; + + lang->messages[msg] = strdup(text); + } + + /* + * Close the file and return... + */ + + if (fp != NULL) + fclose(fp); + + return (lang); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/language.h b/cups/language.h new file mode 100644 index 0000000000..a54424d82c --- /dev/null +++ b/cups/language.h @@ -0,0 +1,200 @@ +/* + * "$Id$" + * + * Multi-language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_LANGUAGE_H_ +# define _CUPS_LANGUAGE_H_ + +/* + * Include necessary headers... + */ + +# include + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +/* + * Messages... + */ + +typedef enum /**** Message Indices ****/ +{ + CUPS_MSG_OK, + CUPS_MSG_CANCEL, + CUPS_MSG_HELP, + CUPS_MSG_QUIT, + CUPS_MSG_CLOSE, + CUPS_MSG_YES, + CUPS_MSG_NO, + CUPS_MSG_ON, + CUPS_MSG_OFF, + CUPS_MSG_SAVE, + CUPS_MSG_DISCARD, + CUPS_MSG_DEFAULT, + CUPS_MSG_OPTIONS, + CUPS_MSG_MORE_INFO, + CUPS_MSG_BLACK, + CUPS_MSG_COLOR, + CUPS_MSG_CYAN, + CUPS_MSG_MAGENTA, + CUPS_MSG_YELLOW, + CUPS_MSG_COPYRIGHT, + CUPS_MSG_GENERAL, + CUPS_MSG_PRINTER, + CUPS_MSG_IMAGE, + CUPS_MSG_HPGL2, + CUPS_MSG_EXTRA, + CUPS_MSG_DOCUMENT, + CUPS_MSG_OTHER, + CUPS_MSG_PRINT_PAGES, + CUPS_MSG_ENTIRE_DOCUMENT, + CUPS_MSG_PAGE_RANGE, + CUPS_MSG_REVERSE_ORDER, + CUPS_MSG_PAGE_FORMAT, + CUPS_MSG_1_UP, + CUPS_MSG_2_UP, + CUPS_MSG_4_UP, + CUPS_MSG_IMAGE_SCALING, + CUPS_MSG_USE_NATURAL_IMAGE_SIZE, + CUPS_MSG_ZOOM_BY_PERCENT, + CUPS_MSG_ZOOM_BY_PPI, + CUPS_MSG_MIRROR_IMAGE, + CUPS_MSG_COLOR_SATURATION, + CUPS_MSG_COLOR_HUE, + CUPS_MSG_FIT_TO_PAGE, + CUPS_MSG_SHADING, + CUPS_MSG_DEFAULT_PEN_WIDTH, + CUPS_MSG_GAMMA_CORRECTION, + CUPS_MSG_BRIGHTNESS, + CUPS_MSG_ADD, + CUPS_MSG_DELETE, + CUPS_MSG_MODIFY, + CUPS_MSG_PRINTER_URI, + CUPS_MSG_PRINTER_NAME, + CUPS_MSG_PRINTER_LOCATION, + CUPS_MSG_PRINTER_INFO, + CUPS_MSG_PRINTER_MAKE_AND_MODEL, + CUPS_MSG_DEVICE_URI, + CUPS_MSG_FORMATTING_PAGE, + CUPS_MSG_PRINTING_PAGE, + CUPS_MSG_INITIALIZING_PRINTER, + CUPS_MSG_PRINTER_STATE, + CUPS_MSG_ACCEPTING_JOBS, + CUPS_MSG_NOT_ACCEPTING_JOBS, + CUPS_MSG_PRINT_JOBS, + CUPS_MSG_CLASS, + CUPS_MSG_LOCAL, + CUPS_MSG_REMOTE, + CUPS_MSG_DUPLEXING, + CUPS_MSG_STAPLING, + CUPS_MSG_FAST_COPIES, + CUPS_MSG_COLLATED_COPIES, + CUPS_MSG_PUNCHING, + CUPS_MSG_COVERING, + CUPS_MSG_BINDING, + CUPS_MSG_SORTING, + CUPS_MSG_SMALL, + CUPS_MSG_MEDIUM, + CUPS_MSG_LARGE, + CUPS_MSG_VARIABLE, + CUPS_MSG_IDLE, + CUPS_MSG_PROCESSING, + CUPS_MSG_STOPPED, + CUPS_MSG_ALL, + CUPS_MSG_ODD, + CUPS_MSG_EVEN_PAGES, + CUPS_MSG_DARKER_LIGHTER, + CUPS_MSG_MEDIA_SIZE, + CUPS_MSG_MEDIA_TYPE, + CUPS_MSG_MEDIA_SOURCE, + CUPS_MSG_ORIENTATION, + CUPS_MSG_PORTRAIT, + CUPS_MSG_LANDSCAPE, + CUPS_MSG_JOB_STATE, + CUPS_MSG_JOB_NAME, + CUPS_MSG_USER_NAME, + CUPS_MSG_PRIORITY, + CUPS_MSG_COPIES, + CUPS_MSG_FILE_SIZE, + CUPS_MSG_PENDING, + CUPS_MSG_OUTPUT_MODE, + CUPS_MSG_RESOLUTION, + CUPS_MSG_HTTP_BASE = 200, + CUPS_MSG_HTTP_END = 505, + CUPS_MSG_MAX +} cups_msg_t; + +typedef enum /**** Language Encodings ****/ +{ + CUPS_US_ASCII, + CUPS_ISO8859_1, + CUPS_ISO8859_2, + CUPS_ISO8859_3, + CUPS_ISO8859_4, + CUPS_ISO8859_5, + CUPS_ISO8859_6, + CUPS_ISO8859_7, + CUPS_ISO8859_8, + CUPS_ISO8859_9, + CUPS_ISO8859_10, + CUPS_UTF8 +} cups_encoding_t; + +typedef struct cups_lang_str /**** Language Cache Structure ****/ +{ + struct cups_lang_str *next; /* Next language in cache */ + int used; /* Number of times this entry has been used. */ + cups_encoding_t encoding; /* Text encoding */ + char language[16]; /* Language/locale name */ + char *messages[CUPS_MSG_MAX]; + /* Message array */ +} cups_lang_t; + + +/* + * Prototypes... + */ + +# ifdef WIN32 +# define cupsLangDefault() cupsLangGet(setlocale(LC_ALL, "")) +# else /* This fix works around bugs in the Linux and HP-UX setlocale() */ +# define cupsLangDefault() cupsLangGet(getenv("LANG")) +# endif /* WIN32 */ + +extern char *cupsLangEncoding(cups_lang_t *lang); +extern void cupsLangFlush(void); +extern void cupsLangFree(cups_lang_t *lang); +extern cups_lang_t *cupsLangGet(const char *language); +# define cupsLangString(lang,msg) (lang)->messages[(msg)] + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_LANGUAGE_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/mark.c b/cups/mark.c new file mode 100644 index 0000000000..8061766bb5 --- /dev/null +++ b/cups/mark.c @@ -0,0 +1,412 @@ +/* + * "$Id$" + * + * Option marking routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * ppdConflicts() - Check to see if there are any conflicts. + * ppdFindChoice() - Return a pointer to an option choice. + * ppdFindMarkedChoice() - Return the marked choice for the specified option. + * ppdFindOption() - Return a pointer to the specified option. + * ppdIsMarked() - Check to see if an option is marked... + * ppdMarkDefaults() - Mark all default options in the PPD file. + * ppdMarkOption() - Mark an option in a PPD file. + * ppd_defaults() - Set the defaults for this group and all sub-groups. + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include "string.h" + + +/* + * Local functions... + */ + +static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g); + + +/* + * 'ppdConflicts()' - Check to see if there are any conflicts. + */ + +int /* O - Number of conflicts found */ +ppdConflicts(ppd_file_t *ppd) /* I - PPD to check */ +{ + int i, j, k, /* Looping variables */ + conflicts; /* Number of conflicts */ + ppd_const_t *c; /* Current constraint */ + ppd_group_t *g, *sg; /* Groups */ + ppd_option_t *o1, *o2; /* Options */ + ppd_choice_t *c1, *c2; /* Choices */ + + + if (ppd == NULL) + return (0); + + /* + * Clear all conflicts... + */ + + conflicts = 0; + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + { + for (j = g->num_options, o1 = g->options; j > 0; j --, o1 ++) + o1->conflicted = 0; + + for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++) + for (k = sg->num_options, o1 = sg->options; k > 0; k --, o1 ++) + o1->conflicted = 0; + } + + /* + * Loop through all of the UI constraints and flag any options + * that conflict... + */ + + for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++) + { + /* + * Grab pointers to the first option... + */ + + o1 = ppdFindOption(ppd, c->option1); + + if (o1 == NULL) + continue; + else if (c->choice1[0] != '\0') + { + /* + * This constraint maps to a specific choice. + */ + + c1 = ppdFindChoice(o1, c->choice1); + } + else + { + /* + * This constraint applies to any choice for this option. + */ + + for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++) + if (c1->marked) + break; + + if (j == 0) + c1 = NULL; + } + + /* + * Grab pointers to the second option... + */ + + o2 = ppdFindOption(ppd, c->option2); + + if (o2 == NULL) + continue; + else if (c->choice2[0] != '\0') + { + /* + * This constraint maps to a specific choice. + */ + + c2 = ppdFindChoice(o2, c->choice2); + } + else + { + /* + * This constraint applies to any choice for this option. + */ + + for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++) + if (c2->marked) + break; + + if (j == 0) + c2 = NULL; + } + + /* + * If both options are marked then there is a conflict... + */ + + if (c1 != NULL && c1->marked && + c2 != NULL && c2->marked) + { + conflicts ++; + o1->conflicted = 1; + o2->conflicted = 1; + } + } + + /* + * Return the number of conflicts found... + */ + + return (conflicts); +} + + +/* + * 'ppdFindChoice()' - Return a pointer to an option choice. + */ + +ppd_choice_t * /* O - Choice pointer or NULL */ +ppdFindChoice(ppd_option_t *o, /* I - Pointer to option */ + const char *choice) /* I - Name of choice */ +{ + int i; /* Looping var */ + ppd_choice_t *c; /* Current choice */ + + + if (o == NULL || choice == NULL) + return (NULL); + + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (strcmp(c->choice, choice) == 0) + return (c); + + return (NULL); +} + + +/* + * 'ppdFindMarkedChoice()' - Return the marked choice for the specified option. + */ + +ppd_choice_t * /* O - Pointer to choice or NULL */ +ppdFindMarkedChoice(ppd_file_t *ppd, /* I - PPD file */ + const char *option) /* I - Keyword/option name */ +{ + int i; /* Looping var */ + ppd_option_t *o; /* Pointer to option */ + ppd_choice_t *c; /* Pointer to choice */ + + + if ((o = ppdFindOption(ppd, option)) == NULL) + return (NULL); + + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (c->marked) + return (c); + + return (NULL); +} + + +/* + * 'ppdFindOption()' - Return a pointer to the specified option. + */ + +ppd_option_t * /* O - Pointer to option or NULL */ +ppdFindOption(ppd_file_t *ppd, /* I - PPD file data */ + const char *option) /* I - Option/Keyword name */ +{ + int i, j, k; /* Looping vars */ + ppd_option_t *o; /* Pointer to option */ + ppd_group_t *g, /* Pointer to group */ + *sg; /* Pointer to subgroup */ + + + if (ppd == NULL || option == NULL) + return (NULL); + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + { + for (j = g->num_options, o = g->options; j > 0; j --, o ++) + if (strcmp(o->keyword, option) == 0) + return (o); + + for (j = g->num_subgroups, sg = g->subgroups; j > 0; j --, sg ++) + for (k = sg->num_options, o = sg->options; k > 0; k --, o ++) + if (strcmp(o->keyword, option) == 0) + return (o); + } + + return (NULL); +} + + +/* + * 'ppdIsMarked()' - Check to see if an option is marked... + */ + +int /* O - Non-zero if option is marked */ +ppdIsMarked(ppd_file_t *ppd, /* I - PPD file data */ + const char *option, /* I - Option/Keyword name */ + const char *choice) /* I - Choice name */ +{ + ppd_option_t *o; /* Option pointer */ + ppd_choice_t *c; /* Choice pointer */ + + + if (ppd == NULL) + return (0); + + if ((o = ppdFindOption(ppd, option)) == NULL) + return (0); + + if ((c = ppdFindChoice(o, choice)) == NULL) + return (0); + + return (c->marked); +} + + +/* + * 'ppdMarkDefaults()' - Mark all default options in the PPD file. + */ + +void +ppdMarkDefaults(ppd_file_t *ppd)/* I - PPD file record */ +{ + int i; /* Looping variables */ + ppd_group_t *g; /* Current group */ + ppd_option_t *o; /* PageSize option */ + + + if (ppd == NULL) + return; + + for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++) + ppd_defaults(ppd, g); +} + + +/* + * 'ppdMarkOption()' - Mark an option in a PPD file. + * + * Notes: + * + * -1 is returned if the given option would conflict with any currently + * selected option. + */ + +int /* O - Number of conflicts */ +ppdMarkOption(ppd_file_t *ppd, /* I - PPD file record */ + const char *option, /* I - Keyword */ + const char *choice) /* I - Option name */ +{ + int i; /* Looping var */ + ppd_option_t *o; /* Option pointer */ + ppd_choice_t *c; /* Choice pointer */ + + + if (ppd == NULL) + return (0); + + if (strcmp(option, "PageSize") == 0 && strncmp(choice, "Custom.", 7) == 0) + { + /* + * Handle variable page sizes... + */ + + ppdPageSize(ppd, choice); + choice = "Custom"; + } + + if ((o = ppdFindOption(ppd, option)) == NULL) + return (0); + + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (strcmp(c->choice, choice) == 0) + break; + + if (i) + { + /* + * Option found; mark it and then handle unmarking any other options. + */ + + c->marked = 1; + + if (o->ui != PPD_UI_PICKMANY) + for (i = o->num_choices, c = o->choices; i > 0; i --, c ++) + if (strcmp(c->choice, choice) != 0) + c->marked = 0; + + if (strcmp(option, "PageSize") == 0 || strcmp(option, "PageRegion") == 0) + { + /* + * Mark current page size... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + ppd->sizes[i].marked = strcmp(ppd->sizes[i].name, choice) == 0; + + /* + * Unmark the current PageSize or PageRegion setting, as appropriate... + */ + + if (strcmp(option, "PageSize") == 0) + { + o = ppdFindOption(ppd, "PageRegion"); + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + else + { + o = ppdFindOption(ppd, "PageSize"); + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + } + } + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppd_defaults()' - Set the defaults for this group and all sub-groups. + */ + +static void +ppd_defaults(ppd_file_t *ppd, /* I - PPD file */ + ppd_group_t *g) /* I - Group to default */ +{ + int i; /* Looping var */ + ppd_option_t *o; /* Current option */ + ppd_group_t *sg; /* Current sub-group */ + + + if (g == NULL) + return; + + for (i = g->num_options, o = g->options; i > 0; i --, o ++) + if (strcmp(o->keyword, "PageRegion") != 0) + ppdMarkOption(ppd, o->keyword, o->defchoice); + + for (i = g->num_subgroups, sg = g->subgroups; i > 0; i --, sg ++) + ppd_defaults(ppd, sg); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/mime.c b/cups/mime.c new file mode 100644 index 0000000000..555d50cd01 --- /dev/null +++ b/cups/mime.c @@ -0,0 +1,617 @@ +/* + * "$Id$" + * + * MIME database file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * mimeDelete() - Delete (free) a MIME database. + * mimeMerge() - Merge a MIME database from disk with the current one. + * mimeNew() - Create a new, empty MIME database. + * load_types() - Load a xyz.types file... + * delete_rules() - Free all memory for the given rule tree. + * load_convs() - Load a xyz.convs file... + * + * Revision History: + * + * $Log: mime.c,v $ + * Revision 1.14 1999/07/12 16:09:38 mike + * Fixed all constant arrays to use "const" modifier. + * + * Revision 1.13 1999/06/18 18:36:10 mike + * Fixed address to 44141 Airport View Drive... + * + * Revision 1.12 1999/04/21 21:19:33 mike + * Changes for HP-UX. + * + * Revision 1.11 1999/04/21 19:31:29 mike + * Changed the directory header stuff to use the autoconf-recommended + * sequence of #ifdef's. + * + * Changed the language routines to look for the LOCALEDIR environment + * variable, and if it is not defined to use the LOCALEDIR string defined + * in config.h. + * + * Revision 1.10 1999/03/01 20:51:53 mike + * Code cleanup - removed extraneous semi-colons... + * + * Revision 1.9 1999/02/26 22:00:51 mike + * Added more debug statements. + * + * Fixed bugs in cupsPrintFile() - wasn't setting the IPP_TAG_MIMETYPE + * value tag for the file type. + * + * Updated conversion filter code to handle wildcards for super-type. + * + * Revision 1.8 1999/02/20 16:04:38 mike + * Updated mime.c to scan directories under WIN32. + * + * Fixed some compiler warnings under WIN32. + * + * Updated VC++ project files. + * + * Updated mime.types and mime.convs files for actual registered + * MIME type names. + * + * Revision 1.7 1999/02/05 17:40:53 mike + * Added IPP client read/write code. + * + * Added string functions missing from some UNIXs. + * + * Added option parsing functions. + * + * Added IPP convenience functions (not implemented yet). + * + * Updated source files to use local string.h as needed (for + * missing string functions) + * + * Revision 1.6 1999/02/01 22:08:39 mike + * Restored original directory-scanning functionality of mimeLoad(). + * + * Revision 1.4 1999/01/27 18:31:56 mike + * Updated PPD routines to handle emulations and patch files. + * + * Added DSC comments to emit output as appropriate. + * + * Revision 1.3 1999/01/24 14:18:43 mike + * Check-in prior to CVS use. + * + * Revision 1.2 1998/08/06 14:38:38 mike + * Finished coding and testing for CUPS 1.0. + * + * Revision 1.1 1998/06/11 20:50:53 mike + * Initial revision + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#include "string.h" +#include "mime.h" + +#if defined(WIN32) || defined(__EMX__) +# include +#elif HAVE_DIRENT_H +# include +typedef struct dirent DIRENT; +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +typedef struct direct DIRENT; +# define NAMLEN(dirent) (dirent)->d_namlen +#endif + + +/* + * Local functions... + */ + +static void load_types(mime_t *mime, char *filename); +static void load_convs(mime_t *mime, char *filename); +static void delete_rules(mime_magic_t *rules); + + +/* + * 'mimeDelete()' - Delete (free) a MIME database. + */ + +void +mimeDelete(mime_t *mime) /* I - MIME database */ +{ + int i; /* Looping var */ + + + if (mime == NULL) + return; + + /* + * Loop through the file types and delete any rules... + */ + + for (i = 0; i < mime->num_types; i ++) + { + delete_rules(mime->types[i]->rules); + free(mime->types[i]); + } + + /* + * Free the types and filters arrays, and then the MIME database structure. + */ + + free(mime->types); + free(mime->filters); + free(mime); +} + + +/* + * 'mimeMerge()' - Merge a MIME database from disk with the current one. + */ + +mime_t * /* O - Updated MIME database */ +mimeMerge(mime_t *mime, /* I - MIME database to add to */ + const char *pathname) /* I - Directory to load */ +{ +#if defined(WIN32) || defined(__EMX__) + HANDLE dir; /* Directory handle */ + WIN32_FIND_DATA dent; /* Directory entry */ + char filename[1024], /* Full filename of types/converts file */ + *pathsep; /* Last character in path */ + + + /* + * First open the directory specified by pathname... Return NULL if nothing + * was read or if the pathname is NULL... + */ + + if (pathname == NULL) + return (NULL); + + strcpy(filename, pathname); + pathsep = filename + strlen(filename); + if (pathsep == filename || + (pathsep[-1] != '/' && pathsep[-1] != '\\')) + { + strcpy(pathsep, "/"); + pathsep ++; + } + + strcpy(pathsep, "*.types"); + + if ((dir = FindFirstFile(filename, &dent)) == 0) + return (NULL); + + /* + * If "mime" is NULL, make a new, blank database... + */ + + if (mime == NULL) + if ((mime = mimeNew()) == NULL) + return (NULL); + + /* + * Read all the .types files... + */ + + do + { + /* + * Load a mime.types file... + */ + + strcpy(pathsep, dent.cFileName); + load_types(mime, filename); + } + while (FindNextFile(dir, &dent)); + + FindClose(dir); + + /* + * Read all the .convs files... + */ + + strcpy(pathsep, "*.convs"); + + if ((dir = FindFirstFile(filename, &dent)) == 0) + return (mime); + + do + { + /* + * Load a mime.convs file... + */ + + strcpy(pathsep, dent.cFileName); + load_convs(mime, filename); + } + while (FindNextFile(dir, &dent)); + + FindClose(dir); + + return (mime); +#else + DIR *dir; /* Directory */ + DIRENT *dent; /* Directory entry */ + char filename[1024]; /* Full filename of types/converts file */ + + + /* + * First open the directory specified by pathname... Return NULL if nothing + * was read or if the pathname is NULL... + */ + + if (pathname == NULL) + return (NULL); + + if ((dir = opendir(pathname)) == NULL) + return (NULL); + + /* + * If "mime" is NULL, make a new, blank database... + */ + + if (mime == NULL) + if ((mime = mimeNew()) == NULL) + return (NULL); + + /* + * Read all the .types files... + */ + + while ((dent = readdir(dir)) != NULL) + { + if (NAMLEN(dent) > 6 && + strcmp(dent->d_name + NAMLEN(dent) - 6, ".types") == 0) + { + /* + * Load a mime.types file... + */ + + sprintf(filename, "%s/%s", pathname, dent->d_name); + load_types(mime, filename); + } + } + + rewinddir(dir); + + /* + * Read all the .convs files... + */ + + while ((dent = readdir(dir)) != NULL) + { + if (NAMLEN(dent) > 6 && + strcmp(dent->d_name + NAMLEN(dent) - 6, ".convs") == 0) + { + /* + * Load a mime.convs file... + */ + + sprintf(filename, "%s/%s", pathname, dent->d_name); + load_convs(mime, filename); + } + } + + closedir(dir); + + return (mime); +#endif /* WIN32 || __EMX__ */ +} + + +/* + * 'mimeNew()' - Create a new, empty MIME database. + */ + +mime_t * /* O - MIME database */ +mimeNew(void) +{ + return ((mime_t *)calloc(1, sizeof(mime_t))); +} + + +/* + * 'load_types()' - Load a xyz.types file... + */ + +static void +load_types(mime_t *mime, /* I - MIME database */ + char *filename) /* I - Types file to load */ +{ + FILE *fp; /* Types file */ + int linelen; /* Length of line */ + char line[65536], /* Input line from file */ + *lineptr, /* Current position in line */ + super[MIME_MAX_SUPER], /* Super-type name */ + type[MIME_MAX_TYPE], /* Type name */ + *temp; /* Temporary pointer */ + mime_type_t *typeptr; /* New MIME type */ + + + /* + * First try to open the file... + */ + + if ((fp = fopen(filename, "r")) == NULL) + return; + + /* + * Then read each line from the file, skipping any comments in the file... + */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + linelen = strlen(line); + + /* + * While the last character in the line is a backslash, continue on to the + * next line (and the next, etc.) + */ + + if (line[linelen - 1] == '\n') + { + line[linelen - 1] = '\0'; + linelen --; + } + + while (line[linelen - 1] == '\\') + { + linelen --; + + if (fgets(line + linelen, sizeof(line) - linelen, fp) == NULL) + line[linelen] = '\0'; + else + { + linelen += strlen(line + linelen); + if (line[linelen - 1] == '\n') + { + line[linelen - 1] = '\0'; + linelen --; + } + } + } + + /* + * Skip blank lines and lines starting with a #... + */ + + if (line[0] == '\n' || line[0] == '#') + continue; + + /* + * Extract the super-type and type names from the beginning of the line. + */ + + lineptr = line; + temp = super; + + while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && + (temp - super + 1) < MIME_MAX_SUPER) + *temp++ = tolower(*lineptr++); + + *temp = '\0'; + + if (*lineptr != '/') + continue; + + lineptr ++; + temp = type; + + while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && + *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) + *temp++ = tolower(*lineptr++); + + *temp = '\0'; + + /* + * Add the type and rules to the MIME database... + */ + + typeptr = mimeAddType(mime, super, type); + mimeAddTypeRule(typeptr, lineptr); + } +} + + +/* + * 'load_convs()' - Load a xyz.convs file... + */ + +static void +load_convs(mime_t *mime, /* I - MIME database */ + char *filename) /* I - Convs file to load */ +{ + int i; /* Looping var */ + FILE *fp; /* Convs file */ + char line[1024], /* Input line from file */ + *lineptr, /* Current position in line */ + super[MIME_MAX_SUPER], /* Super-type name */ + type[MIME_MAX_TYPE], /* Type name */ + *temp, /* Temporary pointer */ + *filter; /* Filter program */ + mime_type_t **temptype, /* MIME type looping var */ + *dsttype; /* Destination MIME type */ + int cost; /* Cost of filter */ + + + /* + * First try to open the file... + */ + + if ((fp = fopen(filename, "r")) == NULL) + return; + + /* + * Then read each line from the file, skipping any comments in the file... + */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * Skip blank lines and lines starting with a #... + */ + + if (line[0] == '\n' || line[0] == '#') + continue; + + /* + * Extract the destination super-type and type names from the middle of + * the line. + */ + + lineptr = line; + while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') + lineptr ++; + + while (*lineptr == ' ' || *lineptr == '\t') + lineptr ++; + + temp = super; + + while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && + (temp - super + 1) < MIME_MAX_SUPER) + *temp++ = tolower(*lineptr++); + + *temp = '\0'; + + if (*lineptr != '/') + continue; + + lineptr ++; + temp = type; + + while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && + *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) + *temp++ = tolower(*lineptr++); + + *temp = '\0'; + + if (*lineptr == '\0' || *lineptr == '\n') + continue; + + if ((dsttype = mimeType(mime, super, type)) == NULL) + continue; + + /* + * Then get the cost and filter program... + */ + + while (*lineptr == ' ' || *lineptr == '\t') + lineptr ++; + + if (*lineptr < '0' || *lineptr > '9') + continue; + + cost = atoi(lineptr); + + while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\0') + lineptr ++; + while (*lineptr == ' ' || *lineptr == '\t') + lineptr ++; + + if (*lineptr == '\0' || *lineptr == '\n') + continue; + + filter = lineptr; + if (filter[strlen(filter) - 1] == '\n') + filter[strlen(filter) - 1] = '\0'; + + /* + * Finally, get the source super-type and type names from the beginning of + * the line. We do it here so we can support wildcards... + */ + + lineptr = line; + temp = super; + + while (*lineptr != '/' && *lineptr != '\n' && *lineptr != '\0' && + (temp - super + 1) < MIME_MAX_SUPER) + *temp++ = tolower(*lineptr++); + + *temp = '\0'; + + if (*lineptr != '/') + continue; + + lineptr ++; + temp = type; + + while (*lineptr != ' ' && *lineptr != '\t' && *lineptr != '\n' && + *lineptr != '\0' && (temp - type + 1) < MIME_MAX_TYPE) + *temp++ = tolower(*lineptr++); + + *temp = '\0'; + + /* + * Add the filter to the MIME database, supporting wildcards as needed... + */ + + for (temptype = mime->types, i = 0; i < mime->num_types; i ++, temptype ++) + if ((super[0] == '*' || strcmp((*temptype)->super, super) == 0) && + (type[0] == '*' || strcmp((*temptype)->type, type) == 0)) + mimeAddFilter(mime, *temptype, dsttype, cost, filter); + } +} + + +/* + * 'delete_rules()' - Free all memory for the given rule tree. + */ + +static void +delete_rules(mime_magic_t *rules) /* I - Rules to free */ +{ + mime_magic_t *next; /* Next rule to free */ + + + /* + * Free the rules list, descending recursively to free any child rules. + */ + + while (rules != NULL) + { + next = rules->next; + + if (rules->child != NULL) + delete_rules(rules->child); + + free(rules); + rules = next; + } +} + + +/* + * End of "$Id$". + */ diff --git a/cups/mime.h b/cups/mime.h new file mode 100644 index 0000000000..a7625d82fb --- /dev/null +++ b/cups/mime.h @@ -0,0 +1,137 @@ +/* + * "$Id$" + * + * MIME type/conversion database definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _MIME_H_ +# define _MIME_H_ + +/* + * C++ magic... + */ + +# ifdef _cplusplus +extern "C" { +# endif /* _cplusplus */ + + +/* + * Constants... + */ + +# define MIME_MAX_SUPER 16 /* Maximum size of supertype name */ +# define MIME_MAX_TYPE 32 /* Maximum size of type name */ +# define MIME_MAX_FILTER 256 /* Maximum size of filter pathname */ +# define MIME_MAX_BUFFER 8192 /* Maximum size of file buffer */ + + +/* + * Types/structures... + */ + +typedef enum +{ + MIME_MAGIC_NOP, /* No operation */ + MIME_MAGIC_AND, /* Logical AND of all children */ + MIME_MAGIC_OR, /* Logical OR of all children */ + MIME_MAGIC_MATCH, /* Filename match */ + MIME_MAGIC_ASCII, /* ASCII characters in range */ + MIME_MAGIC_PRINTABLE, /* Printable characters (32-255) in range */ + MIME_MAGIC_STRING, /* String matches */ + MIME_MAGIC_CHAR, /* Character/byte matches */ + MIME_MAGIC_SHORT, /* Short/16-bit word matches */ + MIME_MAGIC_INT, /* Integer/32-bit word matches */ + MIME_MAGIC_LOCALE /* Current locale matches string */ +} mime_op_t; + +typedef struct mime_magic_str /**** MIME Magic Data ****/ +{ + struct mime_magic_str *prev, /* Previous rule */ + *next, /* Next rule */ + *parent, /* Parent rules */ + *child; /* Child rules */ + short op, /* Operation code (see above) */ + invert; /* Invert the result */ + int offset, /* Offset in file */ + length; /* Length of data */ + union + { + char matchv[64]; /* Match value */ + char localev[64]; /* Locale value */ + char stringv[64]; /* String value */ + char charv; /* Byte value */ + short shortv; /* Short value */ + int intv; /* Integer value */ + } value; +} mime_magic_t; + +typedef struct /**** MIME Type Data ****/ +{ + char super[MIME_MAX_SUPER], /* Super-type name ("image", "application", etc.) */ + type[MIME_MAX_TYPE]; /* Type name ("png", "postscript", etc.) */ + mime_magic_t *rules; /* Rules used to detect this type */ +} mime_type_t; + +typedef struct /**** MIME Conversion Filter Data ****/ +{ + mime_type_t *src, /* Source type */ + *dst; /* Destination type */ + int cost; /* Relative cost */ + char filter[MIME_MAX_FILTER];/* Filter program to use */ +} mime_filter_t; + +typedef struct /**** MIME Database ****/ +{ + int num_types; /* Number of file types */ + mime_type_t **types; /* File types */ + int num_filters; /* Number of type conversion filters */ + mime_filter_t *filters; /* Type conversion filters */ +} mime_t; + + +/* + * Functions... + */ + +extern void mimeDelete(mime_t *mime); +#define mimeLoad(pathname) mimeMerge((mime_t *)0, (pathname)); +extern mime_t *mimeMerge(mime_t *mime, const char *pathname); +extern mime_t *mimeNew(void); + +extern mime_type_t *mimeAddType(mime_t *mime, const char *super, const char *type); +extern int mimeAddTypeRule(mime_type_t *mt, const char *rule); +extern mime_type_t *mimeFileType(mime_t *mime, const char *pathname); +extern mime_type_t *mimeType(mime_t *mime, const char *super, const char *type); + +extern mime_filter_t *mimeAddFilter(mime_t *mime, mime_type_t *src, mime_type_t *dst, + int cost, const char *filter); +extern mime_filter_t *mimeFilter(mime_t *mime, mime_type_t *src, mime_type_t *dst, + int *num_filters); + +# ifdef _cplusplus +} +# endif /* _cplusplus */ +#endif /* !_MIME_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/options.c b/cups/options.c new file mode 100644 index 0000000000..d5d222ce96 --- /dev/null +++ b/cups/options.c @@ -0,0 +1,378 @@ +/* + * "$Id$" + * + * Option routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsAddOption() - Add an option to an option array. + * cupsFreeOptions() - Free all memory used by options. + * cupsGetOption() - Get an option value. + * cupsParseOptions() - Parse options from a command-line argument. + * cupsMarkOptions() - Mark command-line options in a PPD file. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include +#include +#include "string.h" + + +/* + * 'cupsAddOption()' - Add an option to an option array. + */ + +int /* O - Number of options */ +cupsAddOption(const char *name, /* I - Name of option */ + const char *value, /* I - Value of option */ + int num_options, /* I - Number of options */ + cups_option_t **options) /* IO - Pointer to options */ +{ + int i; /* Looping var */ + cups_option_t *temp; /* Pointer to new option */ + + + if (name == NULL || value == NULL || options == NULL) + return (0); + + /* + * Look for an existing option with the same name... + */ + + for (i = 0, temp = *options; i < num_options; i ++, temp ++) + if (strcmp(temp->name, name) == 0) + break; + + if (i >= num_options) + { + /* + * No matching option name... + */ + + if (num_options == 0) + temp = (cups_option_t *)malloc(sizeof(cups_option_t)); + else + temp = (cups_option_t *)realloc(*options, sizeof(cups_option_t) * + (num_options + 1)); + + if (temp == NULL) + return (0); + + *options = temp; + temp += num_options; + temp->name = strdup(name); + num_options ++; + } + else + { + /* + * Match found; free the old value... + */ + + free(temp->value); + } + + temp->value = strdup(value); + + return (num_options); +} + + +/* + * 'cupsFreeOptions()' - Free all memory used by options. + */ + +void +cupsFreeOptions(int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Pointer to options */ +{ + int i; /* Looping var */ + + + if (num_options == 0 || options == NULL) + return; + + for (i = 0; i < num_options; i ++) + { + free(options[i].name); + free(options[i].value); + } + + free(options); +} + + +/* + * 'cupsGetOption()' - Get an option value. + */ + +const char * /* O - Option value or NULL */ +cupsGetOption(const char *name, /* I - Name of option */ + int num_options,/* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i; /* Looping var */ + + + if (name == NULL || num_options == 0 || options == NULL) + return (NULL); + + for (i = 0; i < num_options; i ++) + if (strcmp(options[i].name, name) == 0) + return (options[i].value); + + return (NULL); +} + + +/* + * 'cupsParseOptions()' - Parse options from a command-line argument. + */ + +int /* O - Number of options found */ +cupsParseOptions(const char *arg, /* I - Argument to parse */ + int num_options, /* I - Number of options */ + cups_option_t **options) /* O - Options found */ +{ + char *copyarg, /* Copy of input string */ + *ptr, /* Pointer into string */ + *name, /* Pointer to name */ + *value; /* Pointer to value */ + + + if (arg == NULL || options == NULL) + return (0); + + /* + * Make a copy of the argument string and then divide it up... + */ + + copyarg = strdup(arg); + ptr = copyarg; + + while (*ptr != '\0') + { + /* + * Get the name up to a SPACE, =, or end-of-string... + */ + + name = ptr; + while (!isspace(*ptr) && *ptr != '=' && *ptr != '\0') + ptr ++; + + /* + * Skip trailing spaces... + */ + + while (isspace(*ptr)) + *ptr++ = '\0'; + + if (*ptr != '=') + { + /* + * Start of another option... + */ + + num_options = cupsAddOption(name, "", num_options, options); + continue; + } + + /* + * Remove = and parse the value... + */ + + *ptr++ = '\0'; + + if (*ptr == '\'') + { + /* + * Quoted string constant... + */ + + ptr ++; + value = ptr; + + while (*ptr != '\'' && *ptr != '\0') + ptr ++; + + if (*ptr != '\0') + *ptr++ = '\0'; + } + else if (*ptr == '\"') + { + /* + * Double-quoted string constant... + */ + + ptr ++; + value = ptr; + + while (*ptr != '\"' && *ptr != '\0') + ptr ++; + + if (*ptr != '\0') + *ptr++ = '\0'; + } + else + { + /* + * Normal space-delimited string... + */ + + value = ptr; + + while (!isspace(*ptr) && *ptr != '\0') + ptr ++; + + while (isspace(*ptr)) + *ptr++ = '\0'; + } + + /* + * Add the string value... + */ + + num_options = cupsAddOption(name, value, num_options, options); + } + + /* + * Free the copy of the argument we made and return the number of options + * found. + */ + + free(copyarg); + + return (num_options); +} + + +/* + * 'cupsMarkOptions()' - Mark command-line options in a PPD file. + */ + +int /* O - 1 if conflicting */ +cupsMarkOptions(ppd_file_t *ppd, /* I - PPD file */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i; /* Looping var */ + int conflict; /* Option conflicts */ + char *val, /* Pointer into value */ + *ptr, /* Pointer into string */ + s[255]; /* Temporary string */ + + + conflict = 0; + + for (i = num_options; i > 0; i --, options ++) + if (strcmp(options->name, "media") == 0) + { + /* + * Loop through the option string, separating it at commas and + * marking each individual option. + */ + + for (val = options->value; *val;) + { + /* + * Extract the sub-option from the string... + */ + + for (ptr = s; *val && *val != ',' && (ptr - s) < (sizeof(s) - 1);) + *ptr++ = *val++; + *ptr++ = '\0'; + + if (*val == ',') + val ++; + + /* + * Mark it... + */ + + if (ppdMarkOption(ppd, "PageSize", s)) + conflict = 1; + if (ppdMarkOption(ppd, "InputSlot", s)) + conflict = 1; + if (ppdMarkOption(ppd, "MediaType", s)) + conflict = 1; + if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */ + conflict = 1; + if (strcasecmp(s, "manual") == 0) + if (ppdMarkOption(ppd, "ManualFeed", "True")) + conflict = 1; + } + } + else if (strcmp(options->name, "sides") == 0) + { + if (strcmp(options->value, "one-sided") == 0) + { + if (ppdMarkOption(ppd, "Duplex", "None")) + conflict = 1; + if (ppdMarkOption(ppd, "EFDuplex", "None")) /* EFI */ + conflict = 1; + if (ppdMarkOption(ppd, "KD03Duplex", "None")) /* Kodak */ + conflict = 1; + } + else if (strcmp(options->value, "two-sided-long-edge") == 0) + { + if (ppdMarkOption(ppd, "Duplex", "DuplexNoTumble")) + conflict = 1; + if (ppdMarkOption(ppd, "EFDuplex", "DuplexNoTumble")) /* EFI */ + conflict = 1; + if (ppdMarkOption(ppd, "KD03Duplex", "DuplexNoTumble")) /* Kodak */ + conflict = 1; + } + else if (strcmp(options->value, "two-sided-short-edge") == 0) + { + if (ppdMarkOption(ppd, "Duplex", "DuplexTumble")) + conflict = 1; + if (ppdMarkOption(ppd, "EFDuplex", "DuplexTumble")) /* EFI */ + conflict = 1; + if (ppdMarkOption(ppd, "KD03Duplex", "DuplexTumble")) /* Kodak */ + conflict = 1; + } + } + else if (strcmp(options->name, "resolution") == 0) + { + if (ppdMarkOption(ppd, "Resolution", options->value)) + conflict = 1; + if (ppdMarkOption(ppd, "SetResolution", options->value)) + /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ + conflict = 1; + if (ppdMarkOption(ppd, "JCLResolution", options->value)) /* HP */ + conflict = 1; + if (ppdMarkOption(ppd, "CNRes_PGP", options->value)) /* Canon */ + conflict = 1; + } + else if (ppdMarkOption(ppd, options->name, options->value)) + conflict = 1; + + return (conflict); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/page.c b/cups/page.c new file mode 100644 index 0000000000..89c88926d1 --- /dev/null +++ b/cups/page.c @@ -0,0 +1,189 @@ +/* + * "$Id$" + * + * Page size functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * ppdPageSize() - Get the page size record for the given size. + * ppdPageWidth() - Get the page width for the given size. + * ppdPageLength() - Get the page length for the given size. + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include "string.h" +#include + + +/* + * 'ppdPageSize()' - Get the page size record for the given size. + */ + +ppd_size_t * /* O - Size record for page or NULL */ +ppdPageSize(ppd_file_t *ppd, /* I - PPD file record */ + const char *name) /* I - Size name */ +{ + int i; /* Looping var */ + float w, l; /* Width and length of page */ + char units[255]; /* Page size units... */ + + + if (ppd == NULL) + return (NULL); + + if (name != NULL) + { + if (strncmp(name, "Custom.", 7) == 0 && ppd->variable_sizes) + { + /* + * Find the custom page size... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (strcmp("Custom", ppd->sizes[i].name) == 0) + break; + + if (i == ppd->num_sizes) + return (NULL); + + /* + * Variable size; size name can be one of the following: + * + * Custom.WIDTHxLENGTHin - Size in inches + * Custom.WIDTHxLENGTHcm - Size in centimeters + * Custom.WIDTHxLENGTHmm - Size in millimeters + * Custom.WIDTHxLENGTH[pt] - Size in points + */ + + units[0] = '\0'; + if (sscanf(name + 7, "%fx%f%s", &w, &l, units) < 2) + return (NULL); + + if (strcasecmp(units, "in") == 0) + { + ppd->sizes[i].width = w * 72.0; + ppd->sizes[i].length = l * 72.0; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w * 72.0 - ppd->custom_margins[2]; + ppd->sizes[i].top = l * 72.0 - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "cm") == 0) + { + ppd->sizes[i].width = w * 2.54 * 72.0; + ppd->sizes[i].length = l * 2.54 * 72.0; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w * 2.54 * 72.0 - ppd->custom_margins[2]; + ppd->sizes[i].top = l * 2.54 * 72.0 - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "mm") == 0) + { + ppd->sizes[i].width = w * 25.4 * 72.0; + ppd->sizes[i].length = l * 25.4 * 72.0; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w * 25.4 * 72.0 - ppd->custom_margins[2]; + ppd->sizes[i].top = l * 25.4 * 72.0 - ppd->custom_margins[3]; + } + else + { + ppd->sizes[i].width = w; + ppd->sizes[i].length = l; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w - ppd->custom_margins[2]; + ppd->sizes[i].top = l - ppd->custom_margins[3]; + } + + return (ppd->sizes + i); + } + else + { + /* + * Lookup by name... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (strcmp(name, ppd->sizes[i].name) == 0) + return (ppd->sizes + i); + } + } + else + { + /* + * Find default... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (ppd->sizes[i].marked) + return (ppd->sizes + i); + } + + return (NULL); +} + + +/* + * 'ppdPageWidth()' - Get the page width for the given size. + */ + +float /* O - Width of page in points or 0.0 */ +ppdPageWidth(ppd_file_t *ppd, /* I - PPD file record */ + const char *name) /* I - Size name */ +{ + ppd_size_t *size; /* Page size */ + + + if ((size = ppdPageSize(ppd, name)) == NULL) + return (0.0); + else + return (size->width); +} + + +/* + * 'ppdPageLength()' - Get the page length for the given size. + */ + +float /* O - Length of page in points or 0.0 */ +ppdPageLength(ppd_file_t *ppd, /* I - PPD file */ + const char *name) /* I - Size name */ +{ + ppd_size_t *size; /* Page size */ + + + if ((size = ppdPageSize(ppd, name)) == NULL) + return (0.0); + else + return (size->length); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/ppd.c b/cups/ppd.c new file mode 100644 index 0000000000..c2454405fe --- /dev/null +++ b/cups/ppd.c @@ -0,0 +1,1771 @@ +/* + * "$Id$" + * + * PPD file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This code and any derivative of it may be used and distributed + * freely under the terms of the GNU General Public License when + * used with GNU Ghostscript or its derivatives. Use of the code + * (or any derivative of it) with software other than GNU + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + * + * Contents: + * + * ppdClose() - Free all memory used by the PPD file. + * ppd_free_group() - Free a single UI group. + * ppd_free_option() - Free a single option. + * ppdOpen() - Read a PPD file into memory. + * ppdOpenFd() - Read a PPD file into memory. + * ppdOpenFile() - Read a PPD file into memory. + * ppd_read() - Read a line from a PPD file, skipping comment lines + * as necessary. + * compare_strings() - Compare two strings. + * compare_groups() - Compare two groups. + * compare_options() - Compare two options. + * compare_choices() - Compare two choices. + */ + +/* + * Include necessary headers. + */ + +#include "ppd.h" +#include +#include +#include "string.h" +#include "language.h" +#include "debug.h" + + +/* + * Definitions... + */ + +#if defined(WIN32) || defined(__EMX__) +# define READ_BINARY "rb" /* Open a binary file for reading */ +# define WRITE_BINARY "wb" /* Open a binary file for writing */ +#else +# define READ_BINARY "r" /* Open a binary file for reading */ +# define WRITE_BINARY "w" /* Open a binary file for writing */ +#endif /* WIN32 || __EMX__ */ + +#define safe_free(p) if (p) free(p) /* Safe free macro */ + +#define PPD_KEYWORD 1 /* Line contained a keyword */ +#define PPD_OPTION 2 /* Line contained an option name */ +#define PPD_TEXT 4 /* Line contained human-readable text */ +#define PPD_STRING 8 /* Line contained a string or code */ + + +/* + * Local functions... + */ + +static int compare_strings(char *s, char *t); +static int compare_groups(ppd_group_t *g0, ppd_group_t *g1); +static int compare_options(ppd_option_t *o0, ppd_option_t *o1); +static int compare_choices(ppd_choice_t *c0, ppd_choice_t *c1); +static int ppd_read(FILE *fp, char *keyword, char *option, + char *text, char **string); +static void ppd_decode(char *string); +static void ppd_fix(char *string); +static void ppd_free_group(ppd_group_t *group); +static void ppd_free_option(ppd_option_t *option); +static ppd_group_t *ppd_get_group(ppd_file_t *ppd, char *name); +static ppd_option_t *ppd_get_option(ppd_group_t *group, char *name); +static ppd_choice_t *ppd_add_choice(ppd_option_t *option, char *name); + + +/* + * 'ppdClose()' - Free all memory used by the PPD file. + */ + +void +ppdClose(ppd_file_t *ppd) /* I - PPD file record */ +{ + int i; /* Looping var */ + ppd_emul_t *emul; /* Current emulation */ + ppd_group_t *group; /* Current group */ + char **font; /* Current font */ + + + /* + * Range check the PPD file record... + */ + + if (ppd == NULL) + return; + + /* + * Free all strings at the top level... + */ + + safe_free(ppd->lang_encoding); + safe_free(ppd->lang_version); + safe_free(ppd->modelname); + safe_free(ppd->ttrasterizer); + safe_free(ppd->manufacturer); + safe_free(ppd->product); + safe_free(ppd->nickname); + safe_free(ppd->shortnickname); + + /* + * Free any emulations... + */ + + if (ppd->num_emulations > 0) + { + for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++) + { + safe_free(emul->start); + safe_free(emul->stop); + } + + safe_free(ppd->emulations); + } + + /* + * Free any UI groups, subgroups, and options... + */ + + if (ppd->num_groups > 0) + { + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + ppd_free_group(group); + + safe_free(ppd->groups); + } + + /* + * Free any page sizes... + */ + + if (ppd->num_sizes > 0) + safe_free(ppd->sizes); + + /* + * Free any constraints... + */ + + if (ppd->num_consts > 0) + safe_free(ppd->consts); + + /* + * Free any fonts... + */ + + if (ppd->num_fonts > 0) + { + for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++) + safe_free(*font); + + safe_free(ppd->fonts); + } + + /* + * Free any profiles... + */ + + if (ppd->num_profiles > 0) + safe_free(ppd->profiles); + + /* + * Free the whole record... + */ + + safe_free(ppd); +} + + +/* + * 'ppd_free_group()' - Free a single UI group. + */ + +static void +ppd_free_group(ppd_group_t *group) /* I - Group to free */ +{ + int i; /* Looping var */ + ppd_option_t *option; /* Current option */ + ppd_group_t *subgroup; /* Current sub-group */ + + + if (group->num_options > 0) + { + for (i = group->num_options, option = group->options; + i > 0; + i --, option ++) + ppd_free_option(option); + + safe_free(group->options); + } + + if (group->num_subgroups > 0) + { + for (i = group->num_subgroups, subgroup = group->subgroups; + i > 0; + i --, subgroup ++) + ppd_free_group(subgroup); + + safe_free(group->subgroups); + } +} + + +/* + * 'ppd_free_option()' - Free a single option. + */ + +static void +ppd_free_option(ppd_option_t *option) /* I - Option to free */ +{ + int i; /* Looping var */ + ppd_choice_t *choice; /* Current choice */ + + + if (option->num_choices > 0) + { + for (i = option->num_choices, choice = option->choices; + i > 0; + i --, choice ++) + safe_free(choice->code); + + safe_free(option->choices); + } +} + + +/* + * 'ppd_get_group()' - Find or create the named group as needed. + */ + +static ppd_group_t * /* O - Named group */ +ppd_get_group(ppd_file_t *ppd, /* I - PPD file */ + char *name) /* I - Name of group */ +{ + int i; /* Looping var */ + ppd_group_t *group; /* Group */ + + + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + if (strcmp(group->text, name) == 0) + break; + + if (i == 0) + { + if (ppd->num_groups == 0) + group = malloc(sizeof(ppd_group_t)); + else + group = realloc(ppd->groups, + (ppd->num_groups + 1) * sizeof(ppd_group_t)); + + if (group == NULL) + return (NULL); + + ppd->groups = group; + group += ppd->num_groups; + ppd->num_groups ++; + + memset(group, 0, sizeof(ppd_group_t)); + strncpy(group->text, name, sizeof(group->text) - 1); + } + + return (group); +} + + +/* + * 'ppd_get_option()' - Find or create the named option as needed. + */ + +static ppd_option_t * /* O - Named option */ +ppd_get_option(ppd_group_t *group, /* I - Group */ + char *name) /* I - Name of option */ +{ + int i; /* Looping var */ + ppd_option_t *option; /* Option */ + + + for (i = group->num_options, option = group->options; i > 0; i --, option ++) + if (strcmp(option->keyword, name) == 0) + break; + + if (i == 0) + { + if (group->num_options == 0) + option = malloc(sizeof(ppd_option_t)); + else + option = realloc(group->options, + (group->num_options + 1) * sizeof(ppd_option_t)); + + if (option == NULL) + return (NULL); + + group->options = option; + option += group->num_options; + group->num_options ++; + + memset(option, 0, sizeof(ppd_option_t)); + strncpy(option->keyword, name, sizeof(option->keyword) - 1); + } + + return (option); +} + + +/* + * 'ppd_add_choice()' - Add a choice to an option. + */ + +static ppd_choice_t * /* O - Named choice */ +ppd_add_choice(ppd_option_t *option, /* I - Option */ + char *name) /* I - Name of choice */ +{ + ppd_choice_t *choice; /* Choice */ + + + if (option->num_choices == 0) + choice = malloc(sizeof(ppd_choice_t)); + else + choice = realloc(option->choices, + sizeof(ppd_choice_t) * (option->num_choices + 1)); + + if (choice == NULL) + return (NULL); + + option->choices = choice; + choice += option->num_choices; + option->num_choices ++; + + memset(choice, 0, sizeof(ppd_choice_t)); + strncpy(choice->choice, name, sizeof(choice->choice) - 1); + + return (choice); +} + + +/* + * 'ppd_add_size()' - Add a page size. + */ + +static ppd_size_t * /* O - Named size */ +ppd_add_size(ppd_file_t *ppd, /* I - PPD file */ + char *name) /* I - Name of size */ +{ + ppd_size_t *size; /* Size */ + + + if (ppd->num_sizes == 0) + size = malloc(sizeof(ppd_size_t)); + else + size = realloc(ppd->sizes, sizeof(ppd_size_t) * (ppd->num_sizes + 1)); + + if (size == NULL) + return (NULL); + + ppd->sizes = size; + size += ppd->num_sizes; + ppd->num_sizes ++; + + memset(size, 0, sizeof(ppd_size_t)); + strncpy(size->name, name, sizeof(size->name) - 1); + + return (size); +} + + +/* + * 'ppdOpen()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpen(FILE *fp) /* I - File to read from */ +{ + int i, j, k, m; /* Looping vars */ + int count; /* Temporary count */ + ppd_file_t *ppd; /* PPD file record */ + ppd_group_t *group, /* Current group */ + *subgroup; /* Current sub-group */ + ppd_option_t *option; /* Current option */ + ppd_choice_t *choice; /* Current choice */ + ppd_const_t *constraint; /* Current constraint */ + ppd_size_t *size; /* Current page size */ + int mask; /* Line data mask */ + char keyword[41], /* Keyword from file */ + name[41], /* Option from file */ + text[81], /* Human-readable text from file */ + *string, /* Code/text from file */ + *sptr, /* Pointer into string */ + *nameptr; /* Pointer into name */ + float order; /* Order dependency number */ + ppd_section_t section; /* Order dependency section */ + ppd_profile_t *profile; /* Pointer to color profile */ + char **filter; /* Pointer to filter */ + cups_lang_t *language; /* Default language */ + + + /* + * Get the default language for the user... + */ + + language = cupsLangDefault(); + + /* + * Range check input... + */ + + if (fp == NULL) + return (NULL); + + /* + * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'... + */ + + mask = ppd_read(fp, keyword, name, text, &string); + + if (mask == 0 || + strcmp(keyword, "PPD-Adobe") != 0 || + string == NULL || string[0] != '4') + { + /* + * Either this is not a PPD file, or it is not a 4.x PPD file. + */ + + safe_free(string); + + return (NULL); + } + + DEBUG_printf(("ppdOpen: keyword = %s, string = %08x\n", keyword, string)); + + safe_free(string); + + /* + * Allocate memory for the PPD file record... + */ + + if ((ppd = calloc(sizeof(ppd_file_t), 1)) == NULL) + return (NULL); + + ppd->language_level = 1; + ppd->color_device = 0; + ppd->colorspace = PPD_CS_GRAY; + ppd->landscape = 90; + + /* + * Read lines from the PPD file and add them to the file record... + */ + + group = NULL; + subgroup = NULL; + option = NULL; + choice = NULL; + + while ((mask = ppd_read(fp, keyword, name, text, &string)) != 0) + { +#ifdef DEBUG + printf("mask = %x, keyword = \"%s\"", mask, keyword); + + if (name[0] != '\0') + printf(", name = \"%s\"", name); + + if (text[0] != '\0') + printf(", text = \"%s\"", text); + + if (string != NULL) + { + if (strlen(string) > 40) + printf(", string = %08x", string); + else + printf(", string = \"%s\"", string); + } + + puts(""); +#endif /* DEBUG */ + + if (strcmp(keyword, "LanguageLevel") == 0) + ppd->language_level = atoi(string); + else if (strcmp(keyword, "LanguageEncoding") == 0) + { + ppd->lang_encoding = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "LanguageVersion") == 0) + { + ppd->lang_version = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "Manufacturer") == 0) + { + ppd->manufacturer = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "ModelName") == 0) + { + ppd->modelname = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "NickName") == 0) + { + ppd->nickname = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "Product") == 0) + { + ppd->product = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "ShortNickName") == 0) + { + ppd->shortnickname = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "TTRasterizer") == 0) + { + ppd->ttrasterizer = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "JCLBegin") == 0) + { + ppd_decode(string); /* Decode quoted string */ + ppd->jcl_begin = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "JCLEnd") == 0) + { + ppd_decode(string); /* Decode quoted string */ + ppd->jcl_end = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "JCLToPSInterpreter") == 0) + { + ppd_decode(string); /* Decode quoted string */ + ppd->jcl_ps = string; + string = NULL; /* Don't free this string below */ + } + else if (strcmp(keyword, "AccurateScreensSupport") == 0) + ppd->accurate_screens = strcmp(string, "True") == 0; + else if (strcmp(keyword, "ColorDevice") == 0) + ppd->color_device = strcmp(string, "True") == 0; + else if (strcmp(keyword, "ContoneOnly") == 0) + ppd->contone_only = strcmp(string, "True") == 0; + else if (strcmp(keyword, "DefaultColorSpace") == 0) + { + if (strcmp(string, "CMY") == 0) + ppd->colorspace = PPD_CS_CMY; + else if (strcmp(string, "CMYK") == 0) + ppd->colorspace = PPD_CS_CMYK; + else if (strcmp(string, "RGB") == 0) + ppd->colorspace = PPD_CS_RGB; + else if (strcmp(string, "RGBK") == 0) + ppd->colorspace = PPD_CS_RGBK; + else if (strcmp(string, "N") == 0) + ppd->colorspace = PPD_CS_N; + else + ppd->colorspace = PPD_CS_GRAY; + } + else if (strcmp(keyword, "cupsManualCopies") == 0) + ppd->manual_copies = strcmp(string, "True") == 0; + else if (strcmp(keyword, "cupsModelNumber") == 0) + ppd->model_number = atoi(string); + else if (strcmp(keyword, "cupsColorProfile") == 0) + { + if (ppd->num_profiles == 0) + profile = malloc(sizeof(ppd_profile_t)); + else + profile = realloc(ppd->profiles, sizeof(ppd_profile_t) * + (ppd->num_profiles + 1)); + + ppd->profiles = profile; + profile += ppd->num_profiles; + ppd->num_profiles ++; + + memset(profile, 0, sizeof(ppd_profile_t)); + strncpy(profile->resolution, name, sizeof(profile->resolution) - 1); + strncpy(profile->media_type, text, sizeof(profile->media_type) - 1); + sscanf(string, "%f%f%f%f%f%f%f%f%f%f%f", &(profile->density), + &(profile->gamma), + profile->matrix[0] + 0, profile->matrix[0] + 1, + profile->matrix[0] + 2, profile->matrix[1] + 0, + profile->matrix[1] + 1, profile->matrix[1] + 2, + profile->matrix[2] + 0, profile->matrix[2] + 1, + profile->matrix[2] + 2); + } + else if (strcmp(keyword, "cupsFilter") == 0) + { + if (ppd->num_filters == 0) + filter = malloc(sizeof(char *)); + else + filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1)); + + ppd->filters = filter; + filter += ppd->num_filters; + ppd->num_filters ++; + + /* + * Copy filter string and prevent it from being freed below... + */ + + *filter = string; + string = NULL; + } + else if (strcmp(keyword, "VariablePaperSize") == 0 && + strcmp(string, "True") == 0) + { + ppd->variable_sizes = 1; + + /* + * Add a "Custom" page size entry... + */ + + ppd_add_size(ppd, "Custom"); + + /* + * Add a "Custom" page size option... + */ + + if ((group = ppd_get_group(ppd, + cupsLangString(language, + CUPS_MSG_GENERAL))) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if ((option = ppd_get_option(group, "PageSize")) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if ((choice = ppd_add_choice(option, "Custom")) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + strncpy(choice->text, cupsLangString(language, CUPS_MSG_VARIABLE), + sizeof(choice->text) - 1); + group = NULL; + option = NULL; + } + else if (strcmp(keyword, "MaxMediaWidth") == 0) + ppd->custom_max[0] = atof(string); + else if (strcmp(keyword, "MaxMediaHeight") == 0) + ppd->custom_max[1] = atof(string); + else if (strcmp(keyword, "ParamCustomPageSize") == 0) + { + if (strcmp(name, "Width") == 0) + sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0, + ppd->custom_max + 0); + else if (strcmp(name, "Height") == 0) + sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1, + ppd->custom_max + 1); + } + else if (strcmp(keyword, "HWMargins") == 0) + sscanf(string, "%f%f%f%f", ppd->custom_margins + 0, + ppd->custom_margins + 1, ppd->custom_margins + 2, + ppd->custom_margins + 3); + else if (strcmp(keyword, "CustomPageSize") == 0 && + strcmp(name, "True") == 0 && + ppd->variable_sizes) + { + if ((option = ppdFindOption(ppd, "PageSize")) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if ((choice = ppdFindChoice(option, "Custom")) == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + choice->code = string; + string = NULL; + option = NULL; + } + else if (strcmp(keyword, "LandscapeOrientation") == 0) + { + if (strcmp(string, "Minus90") == 0) + ppd->landscape = -90; + else + ppd->landscape = 90; + } + else if (strcmp(keyword, "Emulators") == 0) + { + for (count = 1, sptr = string; sptr != NULL;) + if ((sptr = strchr(sptr, ' ')) != NULL) + { + count ++; + while (*sptr == ' ') + sptr ++; + } + + ppd->num_emulations = count; + ppd->emulations = calloc(sizeof(ppd_emul_t), count); + + for (i = 0, sptr = string; i < count; i ++) + { + for (nameptr = ppd->emulations[i].name; *sptr != '\0' && *sptr != ' ';) + *nameptr ++ = *sptr ++; + + *nameptr = '\0'; + + while (*sptr == ' ') + sptr ++; + } + } + else if (strncmp(keyword, "StartEmulator_", 14) == 0) + { + ppd_decode(string); + + for (i = 0; i < ppd->num_emulations; i ++) + if (strcmp(keyword + 14, ppd->emulations[i].name) == 0) + { + ppd->emulations[i].start = string; + string = NULL; + } + } + else if (strncmp(keyword, "StopEmulator_", 13) == 0) + { + ppd_decode(string); + + for (i = 0; i < ppd->num_emulations; i ++) + if (strcmp(keyword + 13, ppd->emulations[i].name) == 0) + { + ppd->emulations[i].stop = string; + string = NULL; + } + } + else if (strcmp(keyword, "JobPatchFile") == 0) + { + if (ppd->patches == NULL) + { + ppd->patches = string; + string = NULL; + } + else + { + ppd->patches = realloc(ppd->patches, strlen(ppd->patches) + + strlen(string) + 1); + + strcpy(ppd->patches + strlen(ppd->patches), string); + } + } + else if (strcmp(keyword, "OpenUI") == 0) + { + /* + * Add an option record to the current sub-group, group, or file... + */ + + if (name[0] == '*') + strcpy(name, name + 1); + + if (string == NULL) + { + ppdClose(ppd); + return (NULL); + } + + if (subgroup != NULL) + option = ppd_get_option(subgroup, name); + else if (group == NULL) + { + if (strcmp(name, "Collate") != 0 && + strcmp(name, "Duplex") != 0 && + strcmp(name, "InputSlot") != 0 && + strcmp(name, "ManualFeed") != 0 && + strcmp(name, "MediaType") != 0 && + strcmp(name, "MediaColor") != 0 && + strcmp(name, "MediaWeight") != 0 && + strcmp(name, "OutputBin") != 0 && + strcmp(name, "OutputMode") != 0 && + strcmp(name, "OutputOrder") != 0 && + strcmp(name, "PageSize") != 0 && + strcmp(name, "PageRegion") != 0) + group = ppd_get_group(ppd, cupsLangString(language, CUPS_MSG_EXTRA)); + else + group = ppd_get_group(ppd, cupsLangString(language, CUPS_MSG_GENERAL)); + + if (group == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + option = ppd_get_option(group, name); + group = NULL; + } + else + option = ppd_get_option(group, name); + + if (option == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + /* + * Now fill in the initial information for the option... + */ + + if (strcmp(string, "PickMany") == 0) + option->ui = PPD_UI_PICKMANY; + else if (strcmp(string, "Boolean") == 0) + option->ui = PPD_UI_BOOLEAN; + else + option->ui = PPD_UI_PICKONE; + + if (text[0]) + { + strncpy(option->text, text, sizeof(option->text) - 1); + ppd_fix(option->text); + } + else + { + if (strcmp(name, "PageSize") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SIZE), + sizeof(option->text) - 1); + else if (strcmp(name, "MediaType") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_TYPE), + sizeof(option->text) - 1); + else if (strcmp(name, "InputSlot") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_MEDIA_SOURCE), + sizeof(option->text) - 1); + else if (strcmp(name, "ColorModel") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_OUTPUT_MODE), + sizeof(option->text) - 1); + else if (strcmp(name, "Resolution") == 0) + strncpy(option->text, cupsLangString(language, CUPS_MSG_RESOLUTION), + sizeof(option->text) - 1); + else + strncpy(option->text, name, sizeof(option->text) - 1); + } + + option->section = PPD_ORDER_ANY; + } + else if (strcmp(keyword, "JCLOpenUI") == 0) + { + /* + * Find the JCL group, and add if needed... + */ + + group = ppd_get_group(ppd, "JCL"); + + if (group == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + /* + * Add an option record to the current JCLs... + */ + + if (name[0] == '*') + strcpy(name, name + 1); + + option = ppd_get_option(group, name); + + if (option == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + /* + * Now fill in the initial information for the option... + */ + + if (strcmp(string, "PickMany") == 0) + option->ui = PPD_UI_PICKMANY; + else if (strcmp(string, "Boolean") == 0) + option->ui = PPD_UI_BOOLEAN; + else + option->ui = PPD_UI_PICKONE; + + strncpy(option->text, text, sizeof(option->text) - 1); + + option->section = PPD_ORDER_JCL; + group = NULL; + } + else if (strcmp(keyword, "CloseUI") == 0 || + strcmp(keyword, "JCLCloseUI") == 0) + option = NULL; + else if (strcmp(keyword, "OpenGroup") == 0) + { + /* + * Open a new group... + */ + + if (group != NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if (strchr(string, '/') != NULL) /* Just show human readable text */ + strcpy(string, strchr(string, '/') + 1); + + ppd_decode(string); + ppd_fix(string); + group = ppd_get_group(ppd, string); + } + else if (strcmp(keyword, "CloseGroup") == 0) + group = NULL; + else if (strcmp(keyword, "OpenSubGroup") == 0) + { + /* + * Open a new sub-group... + */ + + if (group == NULL || subgroup != NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if (group->num_subgroups == 0) + subgroup = malloc(sizeof(ppd_group_t)); + else + subgroup = realloc(group->subgroups, + (group->num_subgroups + 1) * sizeof(ppd_group_t)); + + if (subgroup == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + group->subgroups = subgroup; + subgroup += group->num_subgroups; + group->num_subgroups ++; + + memset(subgroup, 0, sizeof(ppd_group_t)); + ppd_decode(string); + ppd_fix(string); + strncpy(subgroup->text, string, sizeof(subgroup->text) - 1); + } + else if (strcmp(keyword, "CloseSubGroup") == 0) + subgroup = NULL; + else if (strcmp(keyword, "OrderDependency") == 0 || + strcmp(keyword, "NonUIOrderDependency") == 0) + { + if (sscanf(string, "%f%s%s", &order, name, keyword) != 3) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + if (keyword[0] == '*') + strcpy(keyword, keyword + 1); + + if (strcmp(name, "ExitServer") == 0) + section = PPD_ORDER_EXIT; + else if (strcmp(name, "Prolog") == 0) + section = PPD_ORDER_PROLOG; + else if (strcmp(name, "DocumentSetup") == 0) + section = PPD_ORDER_DOCUMENT; + else if (strcmp(name, "PageSetup") == 0) + section = PPD_ORDER_PAGE; + else if (strcmp(name, "JCLSetup") == 0) + section = PPD_ORDER_JCL; + else + section = PPD_ORDER_ANY; + + if (option == NULL) + { + /* + * Only valid for Non-UI options... + */ + + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + if (group->text[0] == '\0') + break; + + if (i > 0) + for (i = 0; i < group->num_options; i ++) + if (strcmp(keyword, group->options[i].keyword) == 0) + { + group->options[i].section = section; + group->options[i].order = order; + break; + } + + group = NULL; + } + else + { + option->section = section; + option->order = order; + } + } + else if (strncmp(keyword, "Default", 7) == 0) + { + if (string == NULL) + continue; + + if (strchr(string, '/') != NULL) + *strchr(string, '/') = '\0'; + + if (option == NULL) + { + /* + * Only valid for Non-UI options... + */ + + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + if (group->text[0] == '\0') + break; + + if (i > 0) + for (i = 0; i < group->num_options; i ++) + if (strcmp(keyword, group->options[i].keyword) == 0) + { + strncpy(group->options[i].defchoice, string, + sizeof(group->options[i].defchoice) - 1); + break; + } + + group = NULL; + } + else + strncpy(option->defchoice, string, sizeof(option->defchoice) - 1); + } + else if (strcmp(keyword, "UIConstraints") == 0 || + strcmp(keyword, "NonUIConstraints") == 0) + { + if (ppd->num_consts == 0) + constraint = calloc(sizeof(ppd_const_t), 1); + else + constraint = realloc(ppd->consts, + (ppd->num_consts + 1) * sizeof(ppd_const_t)); + + if (constraint == NULL) + { + ppdClose(ppd); + safe_free(string); + return (NULL); + } + + ppd->consts = constraint; + constraint += ppd->num_consts; + ppd->num_consts ++; + + switch (sscanf(string, "%40s%40s%40s%40s", constraint->option1, + constraint->choice1, constraint->option2, + constraint->choice2)) + { + case 0 : /* Error */ + case 1 : /* Error */ + ppdClose(ppd); + safe_free(string); + break; + + case 2 : /* Two options... */ + if (constraint->option1[0] == '*') + strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->choice1[0] == '*') + strcpy(constraint->option2, constraint->choice1 + 1); + else + strcpy(constraint->option2, constraint->choice1); + + constraint->choice1[0] = '\0'; + constraint->choice2[0] = '\0'; + break; + + case 3 : /* Two options, one choice... */ + if (constraint->option1[0] == '*') + strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->choice1[0] == '*') + { + strcpy(constraint->choice2, constraint->option2); + strcpy(constraint->option2, constraint->choice1 + 1); + constraint->choice1[0] = '\0'; + } + else + { + if (constraint->option2[0] == '*') + strcpy(constraint->option2, constraint->option2 + 1); + + constraint->choice2[0] = '\0'; + } + break; + + case 4 : /* Two options, two choices... */ + if (constraint->option1[0] == '*') + strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->option2[0] == '*') + strcpy(constraint->option2, constraint->option2 + 1); + break; + } + } + else if (strcmp(keyword, "PaperDimension") == 0) + { + if ((size = ppdPageSize(ppd, name)) != NULL) + sscanf(string, "%f%f", &(size->width), &(size->length)); + } + else if (strcmp(keyword, "ImageableArea") == 0) + { + if ((size = ppdPageSize(ppd, name)) != NULL) + sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom), + &(size->right), &(size->top)); + } + else if (option != NULL && + (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) == + (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) + { + if (strcmp(keyword, "PageSize") == 0) + { + /* + * Add a page size... + */ + + ppd_add_size(ppd, name); + } + + /* + * Add the option choice... + */ + + choice = ppd_add_choice(option, name); + + if (mask & PPD_TEXT) + { + strncpy(choice->text, text, sizeof(choice->text) - 1); + ppd_fix(choice->text); + } + else if (strcmp(name, "True") == 0) + strcpy(choice->text, "Yes"); + else if (strcmp(name, "False") == 0) + strcpy(choice->text, "No"); + else + strncpy(choice->text, name, sizeof(choice->text) - 1); + + if (strncmp(keyword, "JCL", 3) == 0) + ppd_decode(string); /* Decode quoted string */ + + choice->code = string; + string = NULL; /* Don't free this string below */ + } + + safe_free(string); + } + +#ifdef DEBUG + if (!feof(fp)) + printf("Premature EOF at %d...\n", ftell(fp)); +#endif /* DEBUG */ + + /* + * Set the option back-pointer for each choice... + */ + + qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t), + (int (*)(const void *, const void *))compare_groups); + + for (i = ppd->num_groups, group = ppd->groups; + i > 0; + i --, group ++) + { + qsort(group->options, group->num_options, sizeof(ppd_option_t), + (int (*)(const void *, const void *))compare_options); + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + qsort(option->choices, option->num_choices, sizeof(ppd_choice_t), + (int (*)(const void *, const void *))compare_choices); + + for (k = 0; k < option->num_choices; k ++) + option->choices[k].option = (void *)option; + } + + qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t), + (int (*)(const void *, const void *))compare_groups); + + for (j = group->num_subgroups, subgroup = group->subgroups; + j > 0; + j --, subgroup ++) + { + qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t), + (int (*)(const void *, const void *))compare_options); + + for (k = group->num_options, option = group->options; + k > 0; + k --, option ++) + { + qsort(option->choices, option->num_choices, sizeof(ppd_choice_t), + (int (*)(const void *, const void *))compare_choices); + + for (m = 0; m < option->num_choices; m ++) + option->choices[m].option = (void *)option; + } + } + } + + return (ppd); +} + + +/* + * 'ppdOpenFd()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpenFd(int fd) /* I - File to read from */ +{ + FILE *fp; /* File pointer */ + ppd_file_t *ppd; /* PPD file record */ + + + /* + * Range check input... + */ + + if (fd < 0) + return (NULL); + + /* + * Try to open the file and parse it... + */ + + if ((fp = fdopen(fd, "r")) != NULL) + { + setbuf(fp, NULL); + + ppd = ppdOpen(fp); + + safe_free(fp); + } + else + ppd = NULL; + + return (ppd); +} + + +/* + * 'ppdOpenFile()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpenFile(const char *filename) /* I - File to read from */ +{ + FILE *fp; /* File pointer */ + ppd_file_t *ppd; /* PPD file record */ + + + /* + * Range check input... + */ + + if (filename == NULL) + return (NULL); + + /* + * Try to open the file and parse it... + */ + + if ((fp = fopen(filename, "r")) != NULL) + { + ppd = ppdOpen(fp); + + fclose(fp); + } + else + ppd = NULL; + + return (ppd); +} + + +/* + * 'compare_strings()' - Compare two strings. + */ + +int /* O - Result of comparison */ +compare_strings(char *s, /* I - First string */ + char *t) /* I - Second string */ +{ + int diff, /* Difference between digits */ + digits; /* Number of digits */ + + + /* + * Loop through both strings, returning only when a difference is + * seen. Also, compare whole numbers rather than just characters, too! + */ + + while (*s && *t) + { + if (isdigit(*s) && isdigit(*t)) + { + /* + * Got a number; start by skipping leading 0's... + */ + + while (*s == '0') + s ++; + while (*t == '0') + t ++; + + /* + * Skip equal digits... + */ + + while (isdigit(*s) && *s == *t) + { + s ++; + t ++; + } + + /* + * Bounce out if *s and *t aren't both digits... + */ + + if (isdigit(*s) && !isdigit(*t)) + return (1); + else if (!isdigit(*s) && isdigit(*t)) + return (-1); + else if (!isdigit(*s) || !isdigit(*t)) + continue; + + if (*s < *t) + diff = -1; + else + diff = 1; + + /* + * Figure out how many more digits there are... + */ + + digits = 0; + + while (isdigit(*s)) + { + digits ++; + s ++; + } + + while (isdigit(*t)) + { + digits --; + t ++; + } + + /* + * Return if the number or value of the digits is different... + */ + + if (digits < 0) + return (-1); + else if (digits > 0) + return (1); + else + return (diff); + } + else if (tolower(*s) < tolower(*t)) + return (-1); + else if (tolower(*s) > tolower(*t)) + return (1); + else + { + s ++; + t ++; + } + } + + /* + * Return the results of the final comparison... + */ + + if (*s) + return (1); + else if (*t) + return (-1); + else + return (0); +} + + +/* + * 'compare_groups()' - Compare two groups. + */ + +static int /* O - Result of comparison */ +compare_groups(ppd_group_t *g0, /* I - First group */ + ppd_group_t *g1) /* I - Second group */ +{ + return (compare_strings(g0->text, g1->text)); +} + + +/* + * 'compare_options()' - Compare two options. + */ + +static int /* O - Result of comparison */ +compare_options(ppd_option_t *o0,/* I - First option */ + ppd_option_t *o1)/* I - Second option */ +{ + return (compare_strings(o0->text, o1->text)); +} + + +/* + * 'compare_choices()' - Compare two choices. + */ + +static int /* O - Result of comparison */ +compare_choices(ppd_choice_t *c0,/* I - First choice */ + ppd_choice_t *c1)/* I - Second choice */ +{ + return (compare_strings(c0->text, c1->text)); +} + + +/* + * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as + * necessary. + */ + +static int /* O - Bitmask of fields read */ +ppd_read(FILE *fp, /* I - File to read from */ + char *keyword, /* O - Keyword from line */ + char *option, /* O - Option from line */ + char *text, /* O - Human-readable text from line */ + char **string) /* O - Code/string data */ +{ + int ch, /* Character from file */ + endquote, /* Waiting for an end quote */ + mask; /* Mask to be returned */ + char *keyptr, /* Keyword pointer */ + *optptr, /* Option pointer */ + *textptr, /* Text pointer */ + *strptr, /* Pointer into string */ + *lineptr, /* Current position in line buffer */ + line[262144]; /* Line buffer (256k) */ + + + /* + * Range check everything... + */ + + if (fp == NULL || keyword == NULL || option == NULL || text == NULL || + string == NULL) + return (0); + + /* + * Now loop until we have a valid line... + */ + + do + { + /* + * Read the line... + */ + + lineptr = line; + endquote = 0; + + while ((ch = getc(fp)) != EOF && + (lineptr - line) < (sizeof(line) - 1)) + { + if (ch == '\r' || ch == '\n') + { + /* + * Line feed or carriage return... + */ + + if (lineptr == line) /* Skip blank lines */ + continue; + + if (ch == '\r') + { + /* + * Check for a trailing line feed... + */ + + if ((ch = getc(fp)) == EOF) + break; + if (ch != 0x0a) + ungetc(ch, fp); + } + + *lineptr++ = '\n'; + + if (!endquote) /* Continue for multi-line text */ + break; + } + else + { + /* + * Any other character... + */ + + *lineptr++ = ch; + + if (ch == '\"') + endquote = !endquote; + } + } + + if (lineptr > line && lineptr[-1] == '\n') + lineptr --; + + *lineptr = '\0'; + + if (ch == EOF && lineptr == line) + return (0); + + /* + * Now parse it... + */ + + mask = 0; + lineptr = line + 1; + + keyword[0] = '\0'; + option[0] = '\0'; + text[0] = '\0'; + *string = NULL; + + if (line[0] != '*') /* All lines start with an asterisk */ + continue; + + if (strncmp(line, "*%", 2) == 0 || /* Comment line */ + strncmp(line, "*?", 2) == 0 || /* Query line */ + strcmp(line, "*End") == 0) /* End of multi-line string */ + continue; + + /* + * Get a keyword... + */ + + keyptr = keyword; + + while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr) && + (keyptr - keyword) < 40) + *keyptr++ = *lineptr++; + + *keyptr = '\0'; + mask |= PPD_KEYWORD; + + if (*lineptr == ' ' || *lineptr == '\t') + { + /* + * Get an option name... + */ + + while (*lineptr == ' ' || *lineptr == '\t') + lineptr ++; + + optptr = option; + + while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' && + *lineptr != '/' && (optptr - option) < 40) + *optptr++ = *lineptr++; + + *optptr = '\0'; + mask |= PPD_OPTION; + + if (*lineptr == '/') + { + /* + * Get human-readable text... + */ + + lineptr ++; + + textptr = text; + + while (*lineptr != '\0' && *lineptr != '\n' && *lineptr != ':' && + (textptr - text) < 80) + *textptr++ = *lineptr++; + + *textptr = '\0'; + ppd_decode(text); + + mask |= PPD_TEXT; + } + } + + if (*lineptr == ':') + { + /* + * Get string... + */ + + *string = malloc(strlen(lineptr) + 1); + + while (*lineptr == ':' || isspace(*lineptr)) + lineptr ++; + + strptr = *string; + + while (*lineptr != '\0') + { + if (*lineptr != '\"') + *strptr++ = *lineptr++; + else + lineptr ++; + } + + *strptr = '\0'; + + mask |= PPD_STRING; + } + } + while (mask == 0); + + return (mask); +} + + +/* + * 'ppd_decode()' - Decode a string value... + */ + +static void +ppd_decode(char *string) /* I - String to decode */ +{ + char *inptr, /* Input pointer */ + *outptr; /* Output pointer */ + + + inptr = string; + outptr = string; + + while (*inptr != '\0') + if (*inptr == '<' && isxdigit(inptr[1])) + { + /* + * Convert hex to 8-bit values... + */ + + inptr ++; + while (isxdigit(*inptr)) + { + if (isalpha(*inptr)) + *outptr = (tolower(*inptr) - 'a' + 10) << 4; + else + *outptr = (*inptr - '0') << 4; + + inptr ++; + + if (isalpha(*inptr)) + *outptr |= tolower(*inptr) - 'a' + 10; + else + *outptr |= *inptr - '0'; + + inptr ++; + outptr ++; + } + + while (*inptr != '>' && *inptr != '\0') + inptr ++; + while (*inptr == '>') + inptr ++; + } + else + *outptr++ = *inptr++; + + *outptr = '\0'; +} + + +/* + * 'ppd_fix()' - Fix WinANSI characters in the range 0x80 to 0x9f to be + * valid ISO-8859-1 characters... + */ + +static void +ppd_fix(char *string) /* IO - String to fix */ +{ + unsigned char *p; /* Pointer into string */ + static unsigned char lut[32] =/* Lookup table for characters */ + { + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 0x20, + 'l', + '`', + '\'', + '^', + '~', + 0x20, /* bar */ + 0x20, /* circumflex */ + 0x20, /* dot */ + 0x20, /* double dot */ + 0x20, + 0x20, /* circle */ + 0x20, /* ??? */ + 0x20, + '\"', /* should be right quotes */ + 0x20, /* ??? */ + 0x20 /* accent */ + }; + + + for (p = (unsigned char *)string; *p; p ++) + if (*p >= 0x80 && *p < 0xa0) + *p = lut[*p - 0x80]; +} + + +/* + * End of "$Id$". + */ diff --git a/cups/ppd.h b/cups/ppd.h new file mode 100644 index 0000000000..75000fe270 --- /dev/null +++ b/cups/ppd.h @@ -0,0 +1,239 @@ +/* + * "$Id$" + * + * PostScript Printer Description definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This code and any derivative of it may be used and distributed + * freely under the terms of the GNU General Public License when + * used with GNU Ghostscript or its derivatives. Use of the code + * (or any derivative of it) with software other than GNU + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + */ + +#ifndef _CUPS_PPD_H_ +# define _CUPS_PPD_H_ + +/* + * Include necessary headers... + */ + +# include + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * PPD version... + */ + +# define PPD_VERSION 4.3 /* Kept in sync with Adobe version number */ + + +/* + * Types and structures... + */ + +typedef enum /**** UI types ****/ +{ + PPD_UI_BOOLEAN, /* True or False option */ + PPD_UI_PICKONE, /* Pick one from a list */ + PPD_UI_PICKMANY /* Pick zero or more from a list */ +} ppd_ui_t; + +typedef enum /**** Order dependency sections ****/ +{ + PPD_ORDER_ANY, /* Option code can be anywhere in the file */ + PPD_ORDER_DOCUMENT, /* ... must be in the DocumentSetup section */ + PPD_ORDER_EXIT, /* ... must be sent prior to the document */ + PPD_ORDER_JCL, /* ... must be sent as a JCL command */ + PPD_ORDER_PAGE, /* ... must be in the PageSetup section */ + PPD_ORDER_PROLOG /* ... must be in the Prolog section */ +} ppd_section_t; + +typedef enum /**** Colorspaces ****/ +{ + PPD_CS_CMYK = -4, /* CMYK colorspace */ + PPD_CS_CMY, /* CMY colorspace */ + PPD_CS_GRAY = 1, /* Grayscale colorspace */ + PPD_CS_RGB = 3, /* RGB colorspace */ + PPD_CS_RGBK, /* RGBK (K = gray) colorspace */ + PPD_CS_N /* DeviceN colorspace */ +} ppd_cs_t; + +typedef struct /**** Option choices ****/ +{ + char marked, /* 0 if not selected, 1 otherwise */ + choice[41], /* Computer-readable option name */ + text[81], /* Human-readable option name */ + *code; /* Code to send for this option */ + void *option; /* Pointer to parent option structure */ +} ppd_choice_t; + +typedef struct /**** Options ****/ +{ + char conflicted, /* 0 if no conflicts exist, 1 otherwise */ + keyword[41], /* Option keyword name ("PageSize", etc.) */ + defchoice[41], /* Default option choice */ + text[81]; /* Human-readable text */ + ppd_ui_t ui; /* Type of UI option */ + ppd_section_t section; /* Section for command */ + float order; /* Order number */ + int num_choices; /* Number of option choices */ + ppd_choice_t *choices; /* Option choices */ +} ppd_option_t; + +typedef struct ppd_group_str /**** Groups ****/ +{ + char text[81]; /* Human-readable group name */ + int num_options; /* Number of options */ + ppd_option_t *options; /* Options */ + int num_subgroups; /* Number of sub-groups */ + struct ppd_group_str *subgroups; + /* Sub-groups (max depth = 1) */ +} ppd_group_t; + +typedef struct /**** Constraints ****/ +{ + char option1[41], /* First keyword */ + choice1[41], /* First option/choice (blank for all) */ + option2[41], /* Second keyword */ + choice2[41]; /* Second option/choice (blank for all) */ +} ppd_const_t; + +typedef struct /**** Page Sizes ****/ +{ + int marked; /* Page size selected? */ + char name[41]; /* Media size option */ + float width, /* Width of media in points */ + length, /* Length of media in points */ + left, /* Left printable margin in points */ + bottom, /* Bottom printable margin in points */ + right, /* Right printable margin in points */ + top; /* Top printable margin in points */ +} ppd_size_t; + +typedef struct /**** Emulators ****/ +{ + char name[41], /* Emulator name */ + *start, /* Code to switch to this emulation */ + *stop; /* Code to stop this emulation */ +} ppd_emul_t; + +typedef struct /**** sRGB Color Profiles ****/ +{ + char resolution[41], /* Resolution or "-" */ + media_type[41]; /* Media type of "-" */ + float density, /* Ink density to use */ + gamma, /* Gamma correction to use */ + matrix[3][3]; /* Transform matrix */ +} ppd_profile_t; + +typedef struct /**** Files ****/ +{ + int language_level, /* Language level of device */ + color_device, /* 1 = color device, 0 = grayscale */ + variable_sizes, /* 1 = supports variable sizes, 0 = doesn't */ + accurate_screens,/* 1 = supports accurate screens, 0 = not */ + contone_only, /* 1 = continuous tone only, 0 = not */ + landscape, /* -90 or 90 */ + model_number, /* Device-specific model number */ + manual_copies; /* 1 = Copies done manually, 0 = hardware */ + ppd_cs_t colorspace; /* Default colorspace */ + char *patches; /* Patch commands to be sent to printer */ + int num_emulations; /* Number of emulations supported */ + ppd_emul_t *emulations; /* Emulations and the code to invoke them */ + char *jcl_begin, /* Start JCL commands */ + *jcl_ps, /* Enter PostScript interpreter */ + *jcl_end, /* End JCL commands */ + *lang_encoding, /* Language encoding */ + *lang_version, /* Language version (English, Spanish, etc.) */ + *modelname, /* Model name (general) */ + *ttrasterizer, /* Truetype rasterizer */ + *manufacturer, /* Manufacturer name */ + *product, /* Product name (from PS RIP/interpreter) */ + *nickname, /* Nickname (specific) */ + *shortnickname; /* Short version of nickname */ + int num_groups; /* Number of UI groups */ + ppd_group_t *groups; /* UI groups */ + int num_sizes; /* Number of page sizes */ + ppd_size_t *sizes; /* Page sizes */ + float custom_min[2], /* Minimum variable page size */ + custom_max[2], /* Maximum variable page size */ + custom_margins[4];/* Margins around page */ + int num_consts; /* Number of UI/Non-UI constraints */ + ppd_const_t *consts; /* UI/Non-UI constraints */ + int num_fonts; /* Number of pre-loaded fonts */ + char **fonts; /* Pre-loaded fonts */ + int num_profiles; /* Number of sRGB color profiles */ + ppd_profile_t *profiles; /* sRGB color profiles */ + int num_filters; /* Number of filters */ + char **filters; /* Filter strings... */ +} ppd_file_t; + + +/* + * Prototypes... + */ + +extern void ppdClose(ppd_file_t *ppd); +extern int ppdConflicts(ppd_file_t *ppd); +extern int ppdEmit(ppd_file_t *ppd, FILE *fp, + ppd_section_t section); +extern int ppdEmitFd(ppd_file_t *ppd, int fd, + ppd_section_t section); +extern int ppdIsMarked(ppd_file_t *ppd, const char *keyword, + const char *option); +extern void ppdMarkDefaults(ppd_file_t *ppd); +extern int ppdMarkOption(ppd_file_t *ppd, const char *keyword, + const char *option); +extern ppd_choice_t *ppdFindChoice(ppd_option_t *o, const char *option); +extern ppd_choice_t *ppdFindMarkedChoice(ppd_file_t *ppd, const char *keyword); +extern ppd_option_t *ppdFindOption(ppd_file_t *ppd, const char *keyword); +extern ppd_file_t *ppdOpen(FILE *fp); +extern ppd_file_t *ppdOpenFd(int fd); +extern ppd_file_t *ppdOpenFile(const char *filename); +extern float ppdPageLength(ppd_file_t *ppd, const char *name); +extern ppd_size_t *ppdPageSize(ppd_file_t *ppd, const char *name); +extern float ppdPageWidth(ppd_file_t *ppd, const char *name); + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_PPD_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/raster.c b/cups/raster.c new file mode 100644 index 0000000000..665472fdfd --- /dev/null +++ b/cups/raster.c @@ -0,0 +1,252 @@ +/* + * "$Id$" + * + * Raster file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights for the CUPS Raster source + * files are outlined in the GNU Library General Public License, located + * in the "pstoraster" directory. If this file is missing or damaged + * please contact Easy Software Products at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This code and any derivative of it may be used and distributed + * freely under the terms of the GNU General Public License when + * used with GNU Ghostscript or its derivatives. Use of the code + * (or any derivative of it) with software other than GNU + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + * + * Contents: + * + * cupsRasterClose() - Close a raster stream. + * cupsRasterOpen() - Open a raster stream. + * cupsRasterReadHeader() - Read a raster page header. + * cupsRasterReadPixels() - Read raster pixels. + * cupsRasterWriteHeader() - Write a raster page header. + * cupsRasterWritePixels() - Write raster pixels. + */ + +/* + * Include necessary headers... + */ + +#include "raster.h" +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'cupsRasterClose()' - Close a raster stream. + */ + +void +cupsRasterClose(cups_raster_t *r) /* I - Stream to close */ +{ + if (r != NULL) + free(r); +} + + +/* + * 'cupsRasterOpen()' - Open a raster stream. + */ + +cups_raster_t * /* O - New stream */ +cupsRasterOpen(int fd, /* I - File descriptor */ + cups_mode_t mode) /* I - Mode */ +{ + cups_raster_t *r; /* New stream */ + + + if ((r = calloc(sizeof(cups_raster_t), 1)) == NULL) + return (NULL); + + r->fd = fd; + r->mode = mode; + + if (mode == CUPS_RASTER_READ) + { + /* + * Open for read - get sync word... + */ + + if (read(fd, &(r->sync), sizeof(r->sync)) < sizeof(r->sync)) + { + free(r); + return (NULL); + } + + if (r->sync != CUPS_RASTER_SYNC && + r->sync != CUPS_RASTER_REVSYNC) + { + free(r); + return (NULL); + } + } + else + { + /* + * Open for write - put sync word... + */ + + r->sync = CUPS_RASTER_SYNC; + if (write(fd, &(r->sync), sizeof(r->sync)) < sizeof(r->sync)) + { + free(r); + return (NULL); + } + } + + return (r); +} + + +/* + * 'cupsRasterReadHeader()' - Read a raster page header. + */ + +unsigned /* O - 1 on success, 0 on fail */ +cupsRasterReadHeader(cups_raster_t *r, /* I - Raster stream */ + cups_page_header_t *h) /* I - Pointer to header data */ +{ + int len; /* Number of words to swap */ + union swap_s /* Swapping structure */ + { + unsigned char b[4]; + unsigned v; + } *s; + + + if (r == NULL || r->mode != CUPS_RASTER_READ) + return (0); + + if (cupsRasterReadPixels(r, (unsigned char *)h, sizeof(cups_page_header_t)) < + sizeof(cups_page_header_t)) + return (0); + + if (r->sync == CUPS_RASTER_REVSYNC) + for (len = (sizeof(cups_page_header_t) - 256) / 4, + s = (union swap_s *)&(h->AdvanceDistance); + len > 0; + len --, s ++) + s->v = (((((s->b[3] << 8) | s->b[2]) << 8) | s->b[1]) << 8) | s->b[0]; + + return (1); +} + + +/* + * 'cupsRasterReadPixels()' - Read raster pixels. + */ + +unsigned /* O - Number of bytes read */ +cupsRasterReadPixels(cups_raster_t *r, /* I - Raster stream */ + unsigned char *p, /* I - Pointer to pixel buffer */ + unsigned len) /* I - Number of bytes to read */ +{ + int bytes; /* Bytes read */ + unsigned remaining; /* Bytes remaining */ + + + if (r == NULL || r->mode != CUPS_RASTER_READ) + return (0); + + remaining = len; + + while (remaining > 0) + { + bytes = read(r->fd, p, remaining); + + if (bytes <= 0) + { + if (errno != EAGAIN && errno != EINTR) + return (0); + else + continue; + } + + remaining -= bytes; + p += bytes; + } + + return (len); +} + + +/* + * 'cupsRasterWriteHeader()' - Write a raster page header. + */ + +unsigned +cupsRasterWriteHeader(cups_raster_t *r, + cups_page_header_t *h) +{ + if (r == NULL || r->mode != CUPS_RASTER_WRITE) + return (0); + + return (cupsRasterWritePixels(r, (unsigned char *)h, + sizeof(cups_page_header_t)) == + sizeof(cups_page_header_t)); +} + + +/* + * 'cupsRasterWritePixels()' - Write raster pixels. + */ + +unsigned /* O - Number of bytes written */ +cupsRasterWritePixels(cups_raster_t *r, /* I - Raster stream */ + unsigned char *p, /* I - Bytes to write */ + unsigned len)/* I - Number of bytes to write */ +{ + int bytes; /* Bytes read */ + unsigned remaining; /* Bytes remaining */ + + + if (r == NULL || r->mode != CUPS_RASTER_WRITE) + return (0); + + remaining = len; + + while (remaining > 0) + { + bytes = write(r->fd, p, remaining); + + if (bytes <= 0) + { + if (errno != EAGAIN && errno != EINTR) + return (0); + else + continue; + } + + remaining -= bytes; + p += bytes; + } + + return (len); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/raster.h b/cups/raster.h new file mode 100644 index 0000000000..a435af3ac9 --- /dev/null +++ b/cups/raster.h @@ -0,0 +1,233 @@ +/* + * "$Id$" + * + * Raster file definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights for the CUPS Raster source + * files are outlined in the GNU Library General Public License, located + * in the "pstoraster" directory. If this file is missing or damaged + * please contact Easy Software Products at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This code and any derivative of it may be used and distributed + * freely under the terms of the GNU General Public License when + * used with GNU Ghostscript or its derivatives. Use of the code + * (or any derivative of it) with software other than GNU + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + */ + +#ifndef _CUPS_RASTER_H_ +# define _CUPS_RASTER_H_ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +/* + * Every non-PostScript printer driver that supports raster images should + * use the application/vnd.cups-raster image file format. Since both the + * PostScript RIP (pstoraster, based on GNU Ghostscript 4.03) and Image RIP + * (imagetoraster, located in the filter directory) use it, using this format + * saves you a lot of work. Also, the PostScript RIP passes any printer + * options that are in a PS file to your driver this way as well... + */ + +/* + * Constants... + */ + +# define CUPS_RASTER_SYNC 0x52615374 /* RaSt */ +# define CUPS_RASTER_REVSYNC 0x74536152 /* tSaR */ + + +/* + * Types... + */ + +typedef enum +{ + CUPS_RASTER_READ, /* Open stream for reading */ + CUPS_RASTER_WRITE /* Open stream for writing */ +} cups_mode_t; + +typedef enum +{ + CUPS_FALSE, /* Logical false */ + CUPS_TRUE /* Logical true */ +} cups_bool_t; + +typedef enum +{ + CUPS_JOG_NONE, /* Never move pages */ + CUPS_JOG_FILE, /* Move pages after this file */ + CUPS_JOG_JOB, /* Move pages after this job */ + CUPS_JOG_SET /* Move pages after this set */ +} cups_jog_t; + +typedef enum +{ + CUPS_ORIENT_0, /* Don't rotate the page */ + CUPS_ORIENT_90, /* Rotate the page counter-clockwise */ + CUPS_ORIENT_180, /* Turn the page upside down */ + CUPS_ORIENT_270 /* Rotate the page clockwise */ +} cups_orient_t; + +typedef enum +{ + CUPS_CUT_NONE, /* Never cut the roll */ + CUPS_CUT_FILE, /* Cut the roll after this file */ + CUPS_CUT_JOB, /* Cut the roll after this job */ + CUPS_CUT_SET, /* Cut the roll after this set */ + CUPS_CUT_PAGE /* Cut the roll after this page */ +} cups_cut_t; + +typedef enum +{ + CUPS_ADVANCE_NONE, /* Never advance the roll */ + CUPS_ADVANCE_FILE, /* Advance the roll after this file */ + CUPS_ADVANCE_JOB, /* Advance the roll after this job */ + CUPS_ADVANCE_SET, /* Advance the roll after this set */ + CUPS_ADVANCE_PAGE /* Advance the roll after this page */ +} cups_adv_t; + +typedef enum +{ + CUPS_EDGE_TOP, /* Leading edge is the top of the page */ + CUPS_EDGE_RIGHT, /* Leading edge is the right of the page */ + CUPS_EDGE_BOTTOM, /* Leading edge is the bottom of the page */ + CUPS_EDGE_LEFT /* Leading edge is the left of the page */ +} cups_edge_t; + +typedef enum +{ + CUPS_ORDER_CHUNKED, /* CMYK CMYK CMYK ... */ + CUPS_ORDER_BANDED, /* CCC MMM YYY KKK ... */ + CUPS_ORDER_PLANAR /* CCC ... MMM ... YYY ... KKK ... */ +} cups_order_t; + +typedef enum +{ + CUPS_CSPACE_W, /* Luminance */ + CUPS_CSPACE_RGB, /* Red, green, blue */ + CUPS_CSPACE_RGBA, /* Red, green, blue, alpha */ + CUPS_CSPACE_K, /* Black */ + CUPS_CSPACE_CMY, /* Cyan, magenta, yellow */ + CUPS_CSPACE_YMC, /* Yellow, magenta, cyan */ + CUPS_CSPACE_CMYK, /* Cyan, magenta, yellow, black */ + CUPS_CSPACE_YMCK, /* Yellow, magenta, cyan, black */ + CUPS_CSPACE_KCMY, /* Black, cyan, magenta, yellow */ + CUPS_CSPACE_KCMYcm, /* Black, cyan, magenta, yellow, * + * light-cyan, light-magenta */ + CUPS_CSPACE_GMCK, /* Gold, magenta, yellow, black */ + CUPS_CSPACE_GMCS, /* Gold, magenta, yellow, silver */ + CUPS_CSPACE_WHITE, /* White ink (as black) */ + CUPS_CSPACE_GOLD, /* Gold foil */ + CUPS_CSPACE_SILVER /* Silver foil */ +} cups_cspace_t; + + +/* + * The page header structure contains the standard PostScript page device + * dictionary, along with some CUPS-specific parameters that are provided + * by the RIPs... + */ + +typedef struct +{ + /**** Standard Page Device Dictionary String Values ****/ + char MediaClass[64]; /* MediaClass string */ + char MediaColor[64]; /* MediaColor string */ + char MediaType[64]; /* MediaType string */ + char OutputType[64]; /* OutputType string */ + + /**** Standard Page Device Dictionary Integer Values ****/ + unsigned AdvanceDistance; /* AdvanceDistance value in points */ + cups_adv_t AdvanceMedia; /* AdvanceMedia value (see above) */ + cups_bool_t Collate; /* Collated copies value */ + cups_cut_t CutMedia; /* CutMedia value (see above) */ + cups_bool_t Duplex; /* Duplexed (double-sided) value */ + unsigned HWResolution[2]; /* Resolution in dots-per-inch */ + unsigned ImagingBoundingBox[4]; /* Pixel region that is painted (points) */ + cups_bool_t InsertSheet; /* InsertSheet value */ + cups_jog_t Jog; /* Jog value (see above) */ + cups_edge_t LeadingEdge; /* LeadingEdge value (see above) */ + unsigned Margins[2]; /* Lower-lefthand margins in points */ + cups_bool_t ManualFeed; /* ManualFeed value */ + unsigned MediaPosition; /* MediaPosition value */ + unsigned MediaWeight; /* MediaWeight value in grams/m^2 */ + cups_bool_t MirrorPrint; /* MirrorPrint value */ + cups_bool_t NegativePrint; /* NegativePrint value */ + unsigned NumCopies; /* Number of copies to produce */ + cups_orient_t Orientation; /* Orientation value (see above) */ + cups_bool_t OutputFaceUp; /* OutputFaceUp value */ + unsigned PageSize[2]; /* Width and length of page in points */ + cups_bool_t Separations; /* Separations value */ + cups_bool_t TraySwitch; /* TraySwitch value */ + cups_bool_t Tumble; /* Tumble value */ + + /**** CUPS Page Device Dictionary Values ****/ + unsigned cupsWidth; /* Width of page image in pixels */ + unsigned cupsHeight; /* Height of page image in pixels */ + unsigned cupsMediaType; /* Media type code */ + unsigned cupsBitsPerColor; /* Number of bits for each color */ + unsigned cupsBitsPerPixel; /* Number of bits for each pixel */ + unsigned cupsBytesPerLine; /* Number of bytes per line */ + cups_order_t cupsColorOrder; /* Order of colors */ + cups_cspace_t cupsColorSpace; /* True colorspace */ + unsigned cupsCompression; /* Device compression to use */ + unsigned cupsRowCount; /* Rows per band */ + unsigned cupsRowFeed; /* Feed between bands */ + unsigned cupsRowStep; /* Spacing between lines */ +} cups_page_header_t; + + +/* + * The raster structure maintains information about a raster data + * stream... + */ + +typedef struct +{ + unsigned sync; /* Sync word from start of stream */ + int fd; /* File descriptor */ + cups_mode_t mode; /* Read/write mode */ +} cups_raster_t; + + +/* + * Prototypes... + */ + +extern void cupsRasterClose(cups_raster_t *r); +extern cups_raster_t *cupsRasterOpen(int fd, cups_mode_t mode); +extern unsigned cupsRasterReadHeader(cups_raster_t *r, + cups_page_header_t *h); +extern unsigned cupsRasterReadPixels(cups_raster_t *r, + unsigned char *p, unsigned len); +extern unsigned cupsRasterWriteHeader(cups_raster_t *r, + cups_page_header_t *h); +extern unsigned cupsRasterWritePixels(cups_raster_t *r, + unsigned char *p, unsigned len); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_RASTER_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/string.c b/cups/string.c new file mode 100644 index 0000000000..4b64cbb4a7 --- /dev/null +++ b/cups/string.c @@ -0,0 +1,125 @@ +/* + * "$Id$" + * + * String functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * strdup() - Duplicate a string. + * strcasecmp() - Do a case-insensitive comparison. + * strncasecmp() - Do a case-insensitive comparison on up to N chars. + */ + +/* + * Include necessary headers... + */ + +#include "string.h" + + +/* + * 'strdup()' - Duplicate a string. + */ + +# ifndef HAVE_STRDUP +char * /* O - New string pointer */ +strdup(const char *s) /* I - String to duplicate */ +{ + char *t; /* New string pointer */ + + + if (s == NULL) + return (NULL); + + if ((t = malloc(strlen(s) + 1)) == NULL) + return (NULL); + + return (strcpy(t, s)); +} +# endif /* !HAVE_STRDUP */ + + +/* + * 'strcasecmp()' - Do a case-insensitive comparison. + */ + +# ifndef HAVE_STRCASECMP +int /* O - Result of comparison (-1, 0, or 1) */ +strcasecmp(const char *s, /* I - First string */ + const char *t) /* I - Second string */ +{ + while (*s != '\0' && *t != '\0') + { + if (tolower(*s) < tolower(*t)) + return (-1); + else if (tolower(*s) > tolower(*t)) + return (1); + + s ++; + t ++; + } + + if (*s == '\0' && *t == '\0') + return (0); + else if (*s != '\0') + return (1); + else + return (-1); +} +# endif /* !HAVE_STRCASECMP */ + +/* + * 'strncasecmp()' - Do a case-insensitive comparison on up to N chars. + */ + +# ifndef HAVE_STRNCASECMP +int /* O - Result of comparison (-1, 0, or 1) */ +strncasecmp(const char *s, /* I - First string */ + const char *t, /* I - Second string */ + size_t n) /* I - Maximum number of characters to compare */ +{ + while (*s != '\0' && *t != '\0' && n > 0) + { + if (tolower(*s) < tolower(*t)) + return (-1); + else if (tolower(*s) > tolower(*t)) + return (1); + + s ++; + t ++; + n --; + } + + if (n == 0) + return (0); + else if (*s == '\0' && *t == '\0') + return (0); + else if (*s != '\0') + return (1); + else + return (-1); +} +# endif /* !HAVE_STRNCASECMP */ + + +/* + * End of "$Id$". + */ diff --git a/cups/string.h b/cups/string.h new file mode 100644 index 0000000000..a5d130d0e9 --- /dev/null +++ b/cups/string.h @@ -0,0 +1,66 @@ +/* + * "$Id$" + * + * String definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_STRING_H_ +# define _CUPS_STRING_H_ + +/* + * Include necessary headers... + */ + +# include +# include + + +/* + * Stuff for WIN32 and OS/2... + */ + +# if defined(WIN32) || defined(__EMX__) +# define strcasecmp stricmp +# define strncasecmp strnicmp +# endif /* WIN32 || __EMX__ */ + + +/* + * Prototypes... + */ + +# ifndef HAVE_STRDUP +extern char *strdup(const char *); +# endif /* !HAVE_STRDUP */ + +# ifndef HAVE_STRCASECMP +extern int strcasecmp(const char *, const char *); +# endif /* !HAVE_STRCASECMP */ + +# ifndef HAVE_STRNCASECMP +extern int strncasecmp(const char *, const char *, size_t n); +# endif /* !HAVE_STRNCASECMP */ + +#endif /* !_CUPS_STRING_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/testhttp.c b/cups/testhttp.c new file mode 100644 index 0000000000..b29c3eb2c5 --- /dev/null +++ b/cups/testhttp.c @@ -0,0 +1,109 @@ +/* + * "$Id$" + * + * HTTP test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry. + */ + +/* + * Include necessary headers... + */ + +#include +#include "http.h" + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + http_t *http; /* HTTP connection */ + http_status_t status; /* Status of GET command */ + char buffer[1024]; /* Input buffer */ + int bytes; /* Number of bytes read */ + FILE *out; /* Output file */ + +#define HOST "dns.easysw.com" +#define PORT 80 + + puts("Connecting to " HOST "..."); + + httpInitialize(); + http = httpConnect(HOST, PORT); + if (http == NULL) + { + puts("Unable to connect to " HOST "!"); + return (1); + } + + puts("Connected to " HOST "..."); + + out = stdout; + + for (i = 1; i < argc; i ++) + { + if (strcmp(argv[i], "-o") == 0) + { + i ++; + out = fopen(argv[i], "wb"); + continue; + } + + printf("Requesting file \"%s\"...\n", argv[i]); + httpClearFields(http); + httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en"); + httpGet(http, argv[i]); + status = httpUpdate(http); + + if (status == HTTP_OK) + puts("GET OK:"); + else + printf("GET failed with status %d...\n", status); + + while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0) + { + fwrite(buffer, bytes, 1, out); + if (out != stdout) + printf("Read %d bytes, %d total...\n", bytes, ftell(out)); + } + } + + puts("Closing connection to server..."); + httpClose(http); + + if (out != stdout) + fclose(out); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/testmime.c b/cups/testmime.c new file mode 100644 index 0000000000..4724ab524c --- /dev/null +++ b/cups/testmime.c @@ -0,0 +1,199 @@ +/* + * "$Id$" + * + * MIME test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for the test program. + */ + +/* + * Include necessary headers... + */ + +#include +#include "mime.h" + + +/* + * Local functions... + */ + +static void print_rules(mime_magic_t *rules); + + +/* + * 'main()' - Main entry for the test program. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + char super[MIME_MAX_SUPER], /* Super-type name */ + type[MIME_MAX_TYPE]; /* Type name */ + mime_t *mime; /* MIME database */ + mime_type_t *src, /* Source type */ + *dst, /* Destination type */ + **types; /* File type array pointer */ + mime_filter_t *filters; /* Filters for the file */ + int num_filters; /* Number of filters for the file */ + + + mime = mimeLoad("../conf"); + + puts("MIME database types:"); + for (i = 0, types = mime->types; i < mime->num_types; i ++, types ++) + { + printf("\t%s/%s: ", (*types)->super, (*types)->type); + print_rules((*types)->rules); + puts(""); + } + + puts(""); + + puts("MIME database filters:"); + for (i = 0, filters = mime->filters; i < mime->num_filters; i ++, filters ++) + printf("\t%s/%s to %s/%s: %s (%d)\n", + filters->src->super, filters->src->type, + filters->dst->super, filters->dst->type, + filters->filter, filters->cost); + + puts(""); + + switch (argc) + { + default : + fputs("Usage: testmime source-file [destination-type]\n", stderr); + return (1); + + case 2 : + src = mimeFileType(mime, argv[1]); + + if (src != NULL) + { + printf("%s: %s/%s\n", argv[1], src->super, src->type); + return (0); + } + else + { + printf("%s: unknown\n", argv[1]); + return (1); + } + + case 3 : + src = mimeFileType(mime, argv[1]); + + sscanf(argv[2], "%[^/]/%s", super, type); + dst = mimeType(mime, super, type); + + filters = mimeFilter(mime, src, dst, &num_filters); + + if (filters == NULL) + { + printf("No filters to convert from %s to %s.\n", argv[1], argv[2]); + return (1); + } + else + { + for (i = 0; i < num_filters; i ++) + if (i < (num_filters - 1)) + printf("%s | ", filters[i].filter); + else + puts(filters[i].filter); + + return (0); + } + } +} + + +/* + * 'print_rules()' - Print the rules for a file type... + */ + +static void +print_rules(mime_magic_t *rules) /* I - Rules to print */ +{ + char logic; /* Logic separator */ + + + if (rules == NULL) + return; + + if (rules->parent == NULL || + rules->parent->op == MIME_MAGIC_OR) + logic = ','; + else + logic = '+'; + + while (rules != NULL) + { + if (rules->prev != NULL) + putchar(logic); + + switch (rules->op) + { + case MIME_MAGIC_MATCH : + printf("match(%s)", rules->value.matchv); + break; + case MIME_MAGIC_LOCALE : + printf("locale(%s)", rules->value.localev); + break; + case MIME_MAGIC_ASCII : + printf("ascii(%d,%d)", rules->offset, rules->length); + break; + case MIME_MAGIC_PRINTABLE : + printf("printable(%d,%d)", rules->offset, rules->length); + break; + case MIME_MAGIC_STRING : + printf("string(%d,%s)", rules->offset, rules->value.stringv); + break; + case MIME_MAGIC_CHAR : + printf("char(%d,%d)", rules->offset, rules->value.charv); + break; + case MIME_MAGIC_SHORT : + printf("short(%d,%d)", rules->offset, rules->value.shortv); + break; + case MIME_MAGIC_INT : + printf("int(%d,%d)", rules->offset, rules->value.intv); + break; + default : + if (rules->child != NULL) + { + putchar('('); + print_rules(rules->child); + putchar(')'); + } + break; + } + + rules = rules->next; + } +} + + + +/* + * End of "$Id$". + */ diff --git a/cups/testmime.dsp b/cups/testmime.dsp new file mode 100644 index 0000000000..d41065c5d9 --- /dev/null +++ b/cups/testmime.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="testmime" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=testmime - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testmime.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testmime.mak" CFG="testmime - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testmime - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "testmime - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "testmime - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 cups.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"testmime.exe" + +!ELSEIF "$(CFG)" == "testmime - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "testmime___Win32_Debug" +# PROP BASE Intermediate_Dir "testmime___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 cupsd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"testmimed.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "testmime - Win32 Release" +# Name "testmime - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\testmime.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\mime.h +# End Source File +# End Group +# End Target +# End Project diff --git a/cups/testppd.c b/cups/testppd.c new file mode 100644 index 0000000000..b2c7bd7e94 --- /dev/null +++ b/cups/testppd.c @@ -0,0 +1,183 @@ +/* + * "$Id$" + * + * PPD test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * Contents: + * + * main() - Main entry for test program. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "string.h" + + +/* + * 'main()' - Main entry for test program. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, j, k, m, n; /* Looping vars */ + const char *filename; /* File to load */ + ppd_file_t *ppd; /* PPD file record */ + ppd_size_t *size; /* Size record */ + ppd_group_t *group; /* UI group */ + ppd_option_t *option; /* Standard UI option */ + ppd_choice_t *choice; /* Standard UI option choice */ + static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" }; + static char *sections[] = { "ANY", "DOCUMENT", "EXIT", + "JCL", "PAGE", "PROLOG" }; + + + /* + * Display PPD files for each file listed on the command-line... + */ + + if (argc == 1) + { + fputs("Usage: ppdtest filename1.ppd [... filenameN.ppd]\n", stderr); + return (1); + } + + for (i = 1; i < argc; i ++) + { + if (strstr(argv[i], ".ppd")) + filename = argv[i]; + else + filename = cupsGetPPD(argv[i]); + + if ((ppd = ppdOpenFile(filename)) == NULL) + { + fprintf(stderr, "Unable to open \'%s\' as a PPD file!\n", filename); + continue; + } + + printf("FILE: %s\n", filename); + printf(" language_level = %d\n", ppd->language_level); + printf(" color_device = %s\n", ppd->color_device ? "TRUE" : "FALSE"); + printf(" variable_sizes = %s\n", ppd->variable_sizes ? "TRUE" : "FALSE"); + printf(" landscape = %d\n", ppd->landscape); + + switch (ppd->colorspace) + { + case PPD_CS_CMYK : + puts(" colorspace = PPD_CS_CMYK"); + break; + case PPD_CS_CMY : + puts(" colorspace = PPD_CS_CMY"); + break; + case PPD_CS_GRAY : + puts(" colorspace = PPD_CS_GRAY"); + break; + case PPD_CS_RGB : + puts(" colorspace = PPD_CS_RGB"); + break; + default : + puts(" colorspace = "); + break; + } + + printf(" num_emulations = %d\n", ppd->num_emulations); + for (j = 0; j < ppd->num_emulations; j ++) + printf(" emulations[%d] = %s\n", j, ppd->emulations[j].name); + + printf(" lang_encoding = %s\n", ppd->lang_encoding); + printf(" lang_version = %s\n", ppd->lang_version); + printf(" modelname = %s\n", ppd->modelname); + printf(" ttrasterizer = %s\n", + ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer); + printf(" manufacturer = %s\n", ppd->manufacturer); + printf(" product = %s\n", ppd->product); + printf(" nickname = %s\n", ppd->nickname); + printf(" shortnickname = %s\n", ppd->shortnickname); + printf(" patches = %d bytes\n", + ppd->patches == NULL ? 0 : strlen(ppd->patches)); + + printf(" num_groups = %d\n", ppd->num_groups); + for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) + { + printf(" group[%d] = %s\n", j, group->text); + + for (k = 0, option = group->options; k < group->num_options; k ++, option ++) + { + printf(" options[%d] = %s (%s) %s %s %.0f\n", k, + option->keyword, option->text, uis[option->ui], + sections[option->section], option->order); + + if (strcmp(option->keyword, "PageSize") == 0 || + strcmp(option->keyword, "PageRegion") == 0) + { + for (m = option->num_choices, choice = option->choices; + m > 0; + m --, choice ++) + { + size = ppdPageSize(ppd, choice->choice); + + if (size == NULL) + printf(" %s (%s) = ERROR", choice->choice, choice->text); + else + printf(" %s (%s) = %.2fx%.2fin (%.1f,%.1f,%.1f,%.1f)", choice->choice, + choice->text, size->width / 72.0, size->length / 72.0, + size->left / 72.0, size->bottom / 72.0, + size->right / 72.0, size->top / 72.0); + + if (strcmp(option->defchoice, choice->choice) == 0) + puts(" *"); + else + putchar('\n'); + } + } + else + { + for (m = option->num_choices, choice = option->choices; + m > 0; + m --, choice ++) + { + printf(" %s (%s)", choice->choice, choice->text); + + if (strcmp(option->defchoice, choice->choice) == 0) + puts(" *"); + else + putchar('\n'); + } + } + } + } + + ppdClose(ppd); + } + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/testppd.dsp b/cups/testppd.dsp new file mode 100644 index 0000000000..18014f7989 --- /dev/null +++ b/cups/testppd.dsp @@ -0,0 +1,102 @@ +# Microsoft Developer Studio Project File - Name="testppd" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=testppd - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "testppd.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "testppd.mak" CFG="testppd - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "testppd - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "testppd - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "testppd - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 cups.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"testppd.exe" + +!ELSEIF "$(CFG)" == "testppd - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "testppd___Win32_Debug" +# PROP BASE Intermediate_Dir "testppd___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 cupsd.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"testppdd.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "testppd - Win32 Release" +# Name "testppd - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\testppd.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ppd.h +# End Source File +# End Group +# End Target +# End Project diff --git a/cups/type.c b/cups/type.c new file mode 100644 index 0000000000..23b110a490 --- /dev/null +++ b/cups/type.c @@ -0,0 +1,1011 @@ +/* + * "$Id$" + * + * MIME typing routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * mimeAddType() - Add a MIME type to a database. + * mimeAddRule() - Add a detection rule for a file type. + * mimeFileType() - Determine the type of a file. + * mimeType() - Lookup a file type. + * compare() - Compare two MIME super/type names. + * checkrules() - Check each rule in a list. + * patmatch() - Pattern matching... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include + +#include "string.h" +#include "mime.h" + + +/* + * Local functions... + */ + +static int compare(mime_type_t **, mime_type_t **); +static int checkrules(const char *, FILE *, mime_magic_t *); +static int patmatch(const char *, const char *); + + +/* + * 'mimeAddType()' - Add a MIME type to a database. + */ + +mime_type_t * /* O - New (or existing) MIME type */ +mimeAddType(mime_t *mime, /* I - MIME database */ + const char *super, /* I - Super-type name */ + const char *type) /* I - Type name */ +{ + mime_type_t *temp, /* New MIME type */ + **types; /* New MIME types array */ + + + /* + * Range check input... + */ + + if (mime == NULL || super == NULL || type == NULL) + return (NULL); + + if (strlen(super) > (MIME_MAX_SUPER - 1) || + strlen(type) > (MIME_MAX_TYPE - 1)) + return (NULL); + + /* + * See if the type already exists; if so, return the existing type... + */ + + if ((temp = mimeType(mime, super, type)) != NULL) + return (temp); + + /* + * The type doesn't exist; add it... + */ + + if ((temp = calloc(1, sizeof(mime_type_t))) == NULL) + return (NULL); + + if (mime->num_types == 0) + types = (mime_type_t **)malloc(sizeof(mime_type_t *)); + else + types = (mime_type_t **)realloc(mime->types, sizeof(mime_type_t *) * (mime->num_types + 1)); + + if (types == NULL) + { + free(temp); + return (NULL); + } + + mime->types = types; + types += mime->num_types; + mime->num_types ++; + + *types = temp; + strcpy(temp->super, super); + strcpy(temp->type, type); + + if (mime->num_types > 1) + qsort(mime->types, mime->num_types, sizeof(mime_type_t *), + (int (*)(const void *, const void *))compare); + + return (temp); +} + + +/* + * 'mimeAddRule()' - Add a detection rule for a file type. + */ + +int /* O - 0 on success, -1 on failure */ +mimeAddTypeRule(mime_type_t *mt, /* I - Type to add to */ + const char *rule) /* I - Rule to add */ +{ + int num_values, /* Number of values seen */ + op, /* Operation code */ + logic, /* Logic for next rule */ + invert; /* Invert following rule? */ + char name[255], /* Name in rule string */ + value[2][255], /* Value in rule string */ + *ptr, /* Position in name or value */ + quote; /* Quote character */ + int length[2]; /* Length of each parameter */ + mime_magic_t *temp, /* New rule */ + *current; /* Current rule */ + + + /* + * Range check input... + */ + + if (mt == NULL || rule == NULL) + return (-1); + + /* + * Find the last rule in the top-level of the rules tree. + */ + + for (current = mt->rules; current != NULL; current = current->next) + if (current->next == NULL) + break; + + /* + * Parse the rules string. Most rules are either a file extension or a + * comparison function: + * + * extension + * function(parameters) + */ + + logic = MIME_MAGIC_NOP; + invert = 0; + + while (*rule != '\0') + { + while (isspace(*rule)) + rule ++; + + if (*rule == '(') + { + logic = MIME_MAGIC_NOP; + rule ++; + } + else if (*rule == ')') + { + if (current == NULL || current->parent == NULL) + return (-1); + + current = current->parent; + + if (current->parent == NULL) + logic = MIME_MAGIC_OR; + else + logic = current->parent->op; + + rule ++; + } + else if (*rule == '+' && current != NULL) + { + if (logic != MIME_MAGIC_AND && + current != NULL && current->prev != NULL && current->prev->prev != NULL) + { + /* + * OK, we have more than 1 rule in the current tree level... Make a + * new group tree and move the previous rule to it... + */ + + if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL) + return (-1); + + temp->op = MIME_MAGIC_AND; + temp->child = current; + temp->parent = current->parent; + current->prev->next = temp; + temp->prev = current->prev; + + current->prev = NULL; + current->parent = temp; + } + else + current->parent->op = MIME_MAGIC_AND; + + logic = MIME_MAGIC_AND; + rule ++; + } + else if (*rule == ',') + { + if (logic != MIME_MAGIC_OR && current != NULL) + { + /* + * OK, we have two possibilities; either this is the top-level rule or + * we have a bunch of AND rules at this level. + */ + + if (current->parent == NULL) + { + /* + * This is the top-level rule; we have to move *all* of the AND rules + * down a level, as AND has precedence over OR. + */ + + if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL) + return (-1); + + while (current->prev != NULL) + { + current->parent = temp; + current = current->prev; + } + + current->parent = temp; + temp->op = MIME_MAGIC_AND; + temp->child = current; + + mt->rules = current = temp; + } + else + { + /* + * This isn't the top rule, so go up one level... + */ + + current = current->parent; + } + } + + logic = MIME_MAGIC_OR; + rule ++; + } + else if (*rule == '!') + { + invert = 1; + rule ++; + } + else if (isalnum(*rule)) + { + /* + * Read an extension name or a function... + */ + + for (ptr = name; isalnum(*rule) && (ptr - name) < (sizeof(name) - 1);) + *ptr++ = *rule++; + + *ptr = '\0'; + num_values = 0; + + if (*rule == '(') + { + /* + * Read function parameters... + */ + + rule ++; + for (num_values = 0; num_values < 2; num_values ++) + { + ptr = value[num_values]; + + while ((ptr - value[num_values]) < (sizeof(value[0]) - 1) && + *rule != '\0' && *rule != ',' && *rule != ')') + { + if (isspace(*rule)) + { + /* + * Ignore whitespace... + */ + + rule ++; + continue; + } + else if (*rule == '\"' || *rule == '\'') + { + /* + * Copy quoted strings literally... + */ + + quote = *rule++; + + while (*rule != '\0' && *rule != quote) + *ptr++ = *rule++; + + if (*rule == quote) + rule ++; + else + return (-1); + } + else if (*rule == '<') + { + rule ++; + + while (*rule != '>' && *rule != '\0') + { + if (isxdigit(rule[0]) && isxdigit(rule[1])) + { + if (isdigit(*rule)) + *ptr = (*rule++ - '0') << 4; + else + *ptr = (tolower(*rule++) - 'a' + 10) << 4; + + if (isdigit(*rule)) + *ptr++ |= *rule++ - '0'; + else + *ptr++ |= tolower(*rule++) - 'a' + 10; + } + else + return (-1); + } + + if (*rule == '>') + rule ++; + else + return (-1); + } + else + *ptr++ = *rule++; + } + + *ptr = '\0'; + length[num_values] = ptr - value[num_values]; + + if (*rule != ',') + break; + + rule ++; + } + + if (*rule != ')') + return (-1); + + rule ++; + + /* + * Figure out the function... + */ + + if (strcmp(name, "match") == 0) + op = MIME_MAGIC_MATCH; + else if (strcmp(name, "ascii") == 0) + op = MIME_MAGIC_ASCII; + else if (strcmp(name, "printable") == 0) + op = MIME_MAGIC_PRINTABLE; + else if (strcmp(name, "string") == 0) + op = MIME_MAGIC_STRING; + else if (strcmp(name, "char") == 0) + op = MIME_MAGIC_CHAR; + else if (strcmp(name, "short") == 0) + op = MIME_MAGIC_SHORT; + else if (strcmp(name, "int") == 0) + op = MIME_MAGIC_INT; + else if (strcmp(name, "locale") == 0) + op = MIME_MAGIC_LOCALE; + else + return (-1); + } + else + { + /* + * This is just a filename match on the extension... + */ + + sprintf(value[0], "*.%s", name); + length[0] = strlen(value[0]); + num_values = 1; + op = MIME_MAGIC_MATCH; + } + + /* + * Add a rule for this operation. + */ + + if ((temp = calloc(1, sizeof(mime_magic_t))) == NULL) + return (-1); + + temp->invert = invert; + if (current != NULL) + { + temp->parent = current->parent; + current->next = temp; + } + else + mt->rules = temp; + + temp->prev = current; + + if (logic == MIME_MAGIC_NOP) + { + /* + * Add parenthetical grouping... + */ + + temp->op = MIME_MAGIC_OR; + + if ((temp->child = calloc(1, sizeof(mime_magic_t))) == NULL) + return (-1); + + temp->child->parent = temp; + + temp = temp->child; + logic = MIME_MAGIC_OR; + } + + /* + * Fill in data for the rule... + */ + + current = temp; + temp->op = op; + invert = 0; + + switch (op) + { + case MIME_MAGIC_MATCH : + if (length[0] > (sizeof(temp->value.matchv) - 1)) + return (-1); + strcpy(temp->value.matchv, value[0]); + break; + case MIME_MAGIC_ASCII : + case MIME_MAGIC_PRINTABLE : + temp->offset = atoi(value[0]); + temp->length = atoi(value[1]); + if (temp->length > MIME_MAX_BUFFER) + temp->length = MIME_MAX_BUFFER; + break; + case MIME_MAGIC_STRING : + temp->offset = atoi(value[0]); + if (length[1] > sizeof(temp->value.stringv)) + return (-1); + temp->length = length[1]; + memcpy(temp->value.stringv, value[1], length[1]); + break; + case MIME_MAGIC_CHAR : + temp->offset = atoi(value[0]); + if (length[1] == 1) + temp->value.charv = value[1][0]; + else + temp->value.charv = atoi(value[1]); + break; + case MIME_MAGIC_SHORT : + temp->offset = atoi(value[0]); + temp->value.shortv = atoi(value[1]); + break; + case MIME_MAGIC_INT : + temp->offset = atoi(value[0]); + temp->value.intv = atoi(value[1]); + break; + case MIME_MAGIC_LOCALE : + if (length[0] > (sizeof(temp->value.localev) - 1)) + return (-1); + + strcpy(temp->value.localev, value[0]); + break; + } + } + else + break; + } + + return (0); +} + + +/* + * 'mimeFileType()' - Determine the type of a file. + */ + +mime_type_t * /* O - Type of file */ +mimeFileType(mime_t *mime, /* I - MIME database */ + const char *pathname) /* I - Name of file to check */ +{ + int i; /* Looping var */ + FILE *fp; /* File pointer */ + mime_type_t **types; /* File types */ + const char *filename; /* Base filename of file */ + + + /* + * Range check input parameters... + */ + + if (mime == NULL || pathname == NULL) + return (NULL); + + /* + * Try to open the file... + */ + + if ((fp = fopen(pathname, "r")) == NULL) + return (NULL); + + /* + * Figure out the filename (without directory portion)... + */ + + if ((filename = strrchr(pathname, '/')) != NULL) + filename ++; + else + filename = pathname; + + /* + * Then check it against all known types... + */ + + for (i = mime->num_types, types = mime->types; i > 0; i --, types ++) + if (checkrules(filename, fp, (*types)->rules)) + break; + + /* + * Finally, close the file and return a match (if any)... + */ + + fclose(fp); + + if (i > 0) + return (*types); + else + return (NULL); +} + + +/* + * 'mimeType()' - Lookup a file type. + */ + +mime_type_t * /* O - Matching file type definition */ +mimeType(mime_t *mime, /* I - MIME database */ + const char *super, /* I - Super-type name */ + const char *type) /* I - Type name */ +{ + mime_type_t key, /* MIME type search key*/ + *keyptr, /* Key pointer... */ + **match; /* Matching pointer */ + + /* + * Range check input... + */ + + if (mime == NULL || super == NULL || type == NULL) + return (NULL); + + if (strlen(super) > (MIME_MAX_SUPER - 1) || + strlen(type) > (MIME_MAX_TYPE - 1)) + return (NULL); + + if (mime->num_types == 0) + return (NULL); + + /* + * Lookup the type in the array... + */ + + strcpy(key.super, super); + strcpy(key.type, type); + keyptr = &key; + + match = (mime_type_t **)bsearch(&keyptr, mime->types, mime->num_types, + sizeof(mime_type_t *), + (int (*)(const void *, const void *))compare); + + if (match == NULL) + return (NULL); + else + return (*match); +} + + +/* + * 'compare()' - Compare two MIME super/type names. + */ + +static int /* O - Result of comparison */ +compare(mime_type_t **t0, /* I - First type */ + mime_type_t **t1) /* I - Second type */ +{ + int i; /* Result of comparison */ + + + if ((i = strcasecmp((*t0)->super, (*t1)->super)) == 0) + i = strcasecmp((*t0)->type, (*t1)->type); + + return (i); +} + + +/* + * 'checkrules()' - Check each rule in a list. + */ + +static int /* O - 1 if match, 0 if no match */ +checkrules(const char *filename, /* I - Filename */ + FILE *fp, /* I - File to check */ + mime_magic_t *rules) /* I - Rules to check */ +{ + int n; /* Looping var */ + int logic, /* Logic to apply */ + result, /* Result of test */ + intv; /* Integer value */ + short shortv; /* Short value */ + unsigned char buffer[MIME_MAX_BUFFER],/* Input buffer */ + *bufptr; /* Current buffer position */ + int bufoffset, /* Offset in file for buffer */ + buflength; /* Length of data in buffer */ + + + if (rules == NULL) + return (0); + + if (rules->parent == NULL) + logic = MIME_MAGIC_OR; + else + logic = rules->parent->op; + + bufoffset = -1; + + while (rules != NULL) + { + /* + * Compute the result of this rule... + */ + + switch (rules->op) + { + case MIME_MAGIC_MATCH : + result = patmatch(filename, rules->value.matchv); + break; + + case MIME_MAGIC_ASCII : + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset || + (rules->offset + rules->length) > (bufoffset + buflength)) + { + /* + * Reload file buffer... + */ + + fseek(fp, rules->offset, SEEK_SET); + buflength = fread(buffer, 1, sizeof(buffer), fp); + bufoffset = rules->offset; + } + + /* + * Test for ASCII printable characters plus standard control chars. + */ + + if ((rules->offset + rules->length) > (bufoffset + buflength)) + n = bufoffset + buflength - rules->offset; + else + n = rules->length; + + bufptr = buffer + rules->offset - bufoffset; + while (n > 0) + if ((*bufptr >= 32 && *bufptr <= 126) || + (*bufptr >= 8 && *bufptr <= 13) || + *bufptr == 26 || *bufptr == 27) + { + n --; + bufptr ++; + } + else + break; + + result = (n == 0); + break; + + case MIME_MAGIC_PRINTABLE : + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset || + (rules->offset + rules->length) > (bufoffset + buflength)) + { + /* + * Reload file buffer... + */ + + fseek(fp, rules->offset, SEEK_SET); + buflength = fread(buffer, 1, sizeof(buffer), fp); + bufoffset = rules->offset; + } + + /* + * Test for ASCII printable characters plus standard control chars. + */ + + if ((rules->offset + rules->length) > (bufoffset + buflength)) + n = bufoffset + buflength - rules->offset; + else + n = rules->length; + + bufptr = buffer + rules->offset - bufoffset; + + while (n > 0) + if ((*bufptr >= 160 && *bufptr <= 254) || + (*bufptr >= 32 && *bufptr <= 126) || + (*bufptr >= 8 && *bufptr <= 13) || + *bufptr == 26 || *bufptr == 27) + { + n --; + bufptr ++; + } + else + break; + + result = (n == 0); + break; + + case MIME_MAGIC_STRING : + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset || + (rules->offset + rules->length) > (bufoffset + buflength)) + { + /* + * Reload file buffer... + */ + + fseek(fp, rules->offset, SEEK_SET); + buflength = fread(buffer, 1, sizeof(buffer), fp); + bufoffset = rules->offset; + } + + /* + * Compare the buffer against the string. If the file is too + * short then don't compare - it can't match... + */ + + if ((rules->offset + rules->length) > (bufoffset + buflength)) + result = 0; + else + result = (memcmp(buffer + rules->offset - bufoffset, + rules->value.stringv, rules->length) == 0); + break; + + case MIME_MAGIC_CHAR : + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset) + { + /* + * Reload file buffer... + */ + + fseek(fp, rules->offset, SEEK_SET); + buflength = fread(buffer, 1, sizeof(buffer), fp); + bufoffset = rules->offset; + } + + /* + * Compare the character values; if the file is too short, it + * can't match... + */ + + if (buflength < 1) + result = 0; + else + result = (buffer[rules->offset - bufoffset] == rules->value.charv); + break; + + case MIME_MAGIC_SHORT : + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset || + (rules->offset + 2) > (bufoffset + buflength)) + { + /* + * Reload file buffer... + */ + + fseek(fp, rules->offset, SEEK_SET); + buflength = fread(buffer, 1, sizeof(buffer), fp); + bufoffset = rules->offset; + } + + /* + * Compare the short values; if the file is too short, it + * can't match... + */ + + if (buflength < 2) + result = 0; + else + { + bufptr = buffer + rules->offset - bufoffset; + shortv = (bufptr[0] << 8) | bufptr[1]; + result = (shortv == rules->value.shortv); + } + break; + + case MIME_MAGIC_INT : + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset || + (rules->offset + 4) > (bufoffset + buflength)) + { + /* + * Reload file buffer... + */ + + fseek(fp, rules->offset, SEEK_SET); + buflength = fread(buffer, 1, sizeof(buffer), fp); + bufoffset = rules->offset; + } + + /* + * Compare the int values; if the file is too short, it + * can't match... + */ + + if (buflength < 4) + result = 0; + else + { + bufptr = buffer + rules->offset - bufoffset; + intv = (((((bufptr[0] << 8) | bufptr[1]) << 8) | bufptr[2]) << 8) | + bufptr[3];; + result = (intv == rules->value.intv); + } + break; + + case MIME_MAGIC_LOCALE : + result = (strcmp(rules->value.localev, setlocale(LC_ALL, NULL)) == 0); + break; + + default : + if (rules->child != NULL) + result = checkrules(filename, fp, rules->child); + else + result = 0; + break; + } + + /* + * If the logic is inverted, invert the result... + */ + + if (rules->invert) + result = !result; + + /* + * OK, now if the current logic is OR and this result is true, the this + * rule set is true. If the current logic is AND and this result is false, + * the the rule set is false... + */ + + if ((result && logic == MIME_MAGIC_OR) || + (!result && logic == MIME_MAGIC_AND)) + return (result); + + /* + * Otherwise the jury is still out on this one, so move to the next rule. + */ + + rules = rules->next; + } + + return (result); +} + + +/* + * 'patmatch()' - Pattern matching... + */ + +static int /* O - 1 if match, 0 if no match */ +patmatch(const char *s, /* I - String to match against */ + const char *pat) /* I - Pattern to match against */ +{ + /* + * Range check the input... + */ + + if (s == NULL || pat == NULL) + return (0); + + /* + * Loop through the pattern and match strings, and stop if we come to a + * point where the strings don't match or we find a complete match. + */ + + while (*s != '\0' && *pat != '\0') + { + if (*pat == '*') + { + /* + * Wildcard - 0 or more characters... + */ + + pat ++; + if (*pat == '\0') + return (1); /* Last pattern char is *, so everything matches now... */ + + /* + * Test all remaining combinations until we get to the end of the string. + */ + + while (*s != '\0') + { + if (patmatch(s, pat)) + return (1); + + s ++; + } + } + else if (*pat == '?') + { + /* + * Wildcard - 1 character... + */ + + pat ++; + s ++; + continue; + } + else if (*pat == '[') + { + /* + * Match a character from the input set [chars]... + */ + + pat ++; + while (*pat != ']' && *pat != '\0') + if (*s == *pat) + break; + else + pat ++; + + if (*pat == ']' || *pat == '\0') + return (0); + + while (*pat != ']' && *pat != '\0') + pat ++; + + if (*pat == ']') + pat ++; + + continue; + } + else if (*pat == '\\') + { + /* + * Handle quoted characters... + */ + + pat ++; + } + + /* + * Stop if the pattern and string don't match... + */ + + if (*pat++ != *s++) + return (0); + } + + /* + * Done parsing the pattern and string; return 1 if the last character matches + * and 0 otherwise... + */ + + return (*s == *pat); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/usersys.c b/cups/usersys.c new file mode 100644 index 0000000000..d837f2e9ea --- /dev/null +++ b/cups/usersys.c @@ -0,0 +1,175 @@ +/* + * "$Id$" + * + * User, system, and password routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include +#include +#include + + +#if defined(WIN32) || defined(__EMX__) +/* + * WIN32 and OS/2 username and password stuff... + */ + +/* + * 'cupsUser()' - Return the current user's name. + */ + +const char * /* O - User name */ +cupsUser(void) +{ + return ("WindowsUser"); +} + + +/* + * 'cupsGetPassword()' - Get a password from the user... + */ + +const char * /* O - Password */ +cupsGetPassword(const char *prompt) /* I - Prompt string */ +{ + return (NULL); +} +#else +/* + * UNIX username and password stuff... + */ + +# include + +/* + * 'cupsUser()' - Return the current user's name. + */ + +const char * /* O - User name */ +cupsUser(void) +{ + struct passwd *pwd; /* User/password entry */ + + + /* + * Rewind the password file... + */ + + setpwent(); + + /* + * Lookup the password entry for the current user. + */ + + if ((pwd = getpwuid(getuid())) == NULL) + return ("unknown"); /* Unknown user! */ + + /* + * Rewind the password file again and return the username... + */ + + setpwent(); + + return (pwd->pw_name); +} + + +/* + * 'cupsGetPassword()' - Get a password from the user... + */ + +const char * /* O - Password */ +cupsGetPassword(const char *prompt) /* I - Prompt string */ +{ + return (getpass(prompt)); +} +#endif /* WIN32 || __EMX__ */ + + +/* + * 'cupsServer()' - Return the hostname of the default server... + */ + +const char * /* O - Server name */ +cupsServer(void) +{ + FILE *fp; /* cupsd.conf file */ + char *server; /* Pointer to server name */ + static char line[1024]; /* Line from file */ + + + /* + * First see if the CUPS_SERVER environment variable is set... + */ + + if ((server = getenv("CUPS_SERVER")) != NULL) + return (server); + + /* + * Next check to see if we have a cupsd.conf file... + */ + + if ((fp = fopen(CUPS_SERVERROOT "/conf/cupsd.conf", "r")) == NULL) + return ("localhost"); + + /* + * Read the cupsd.conf file and look for a ServerName line... + */ + + while (fgets(line, sizeof(line), fp) != NULL) + if (strncmp(line, "ServerName ", 11) == 0) + { + /* + * Got it! Drop any trailing newline and find the name... + */ + + server = line + strlen(line) - 1; + if (*server == '\n') + *server = '\0'; + + for (server = line + 11; isspace(*server); server ++); + + if (*server) + return (server); + } + + /* + * Didn't see a ServerName line, so return "localhost"... + */ + + fclose(fp); + + return ("localhost"); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/util.c b/cups/util.c new file mode 100644 index 0000000000..e298499cff --- /dev/null +++ b/cups/util.c @@ -0,0 +1,986 @@ +/* + * "$Id$" + * + * Printing utilities for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsCancelJob() - Cancel a print job. + * cupsDoFileRequest() - Do an IPP request... + * cupsGetClasses() - Get a list of printer classes. + * cupsGetDefault() - Get the default printer or class. + * cupsGetPPD() - Get the PPD file for a printer. + * cupsGetPrinters() - Get a list of printers. + * cupsPrintFile() - Print a file to a printer or class. + * cups_connect() - Connect to the specified host... + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "ipp.h" +#include "language.h" +#include "string.h" +#include "debug.h" +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local globals... + */ + +static http_t *cups_server = NULL; + + +/* + * Local functions... + */ + +static char *cups_connect(const char *name, char *printer, char *hostname); + + +/* + * 'cupsCancelJob()' - Cancel a print job. + */ + +int /* O - 1 on success, 0 on failure */ +cupsCancelJob(const char *name, /* I - Name of printer or class */ + int job) /* I - Job ID */ +{ + char printer[HTTP_MAX_URI], /* Printer name */ + hostname[HTTP_MAX_URI], /* Hostname */ + uri[HTTP_MAX_URI]; /* Printer URI */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + cups_lang_t *language; /* Language info */ + + + /* + * See if we can connect to the server... + */ + + if (!cups_connect(name, printer, hostname)) + return (0); + + /* + * Build an IPP_CANCEL_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * job-id + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_CANCEL_JOB; + 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 != NULL ? language->language : "C"); + + sprintf(uri, "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", job); + + /* + * Do the request... + */ + + if ((response = cupsDoRequest(cups_server, request, "/jobs/")) == NULL) + return (0); + + ippDelete(response); + return (1); +} + + +/* + * 'cupsDoFileRequest()' - Do an IPP request... + */ + +ipp_t * /* O - Response data */ +cupsDoFileRequest(http_t *http, /* I - HTTP connection to server */ + ipp_t *request, /* I - IPP request */ + const char *resource, /* I - HTTP resource for POST */ + const char *filename) /* I - File to send or NULL */ +{ + ipp_t *response; /* IPP response data */ + char length[255]; /* Content-Length field */ + http_status_t status; /* Status of HTTP request */ + FILE *file; /* File to send */ + struct stat fileinfo; /* File information */ + int bytes; /* Number of bytes read/written */ + char buffer[8192]; /* Output buffer */ + const char *password; /* Password string */ + char plain[255], /* Plaintext username:password */ + encode[255]; /* Encoded username:password */ + static char authstring[255] = ""; + /* Authorization string */ + + + DEBUG_printf(("cupsDoFileRequest(%08x, %08s, \'%s\', \'%s\')\n", + http, request, resource, filename ? filename : "(null)")); + + /* + * See if we have a file to send... + */ + + if (filename != NULL) + { + if (stat(filename, &fileinfo)) + { + /* + * Can't get file information! + */ + + ippDelete(request); + return (NULL); + } + + if ((file = fopen(filename, "rb")) == NULL) + { + /* + * Can't open file! + */ + + ippDelete(request); + return (NULL); + } + } + + /* + * Loop until we can send the request without authorization problems. + */ + + response = NULL; + + while (response == NULL) + { + DEBUG_puts("cupsDoFileRequest: setup..."); + + /* + * Setup the HTTP variables needed... + */ + + if (filename != NULL) + sprintf(length, "%u", ippLength(request) + (size_t)fileinfo.st_size); + else + sprintf(length, "%u", ippLength(request)); + + httpClearFields(http); + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, authstring); + + /* + * Try the request... + */ + + DEBUG_puts("cupsDoFileRequest: post..."); + + if (httpPost(http, resource)) + { + httpReconnect(http); + continue; + } + + /* + * Send the IPP data and wait for the response... + */ + + DEBUG_puts("cupsDoFileRequest: ipp write..."); + + request->state = IPP_IDLE; + if (ippWrite(http, request) != IPP_ERROR) + if (filename != NULL) + { + DEBUG_puts("cupsDoFileRequest: file write..."); + + /* + * Send the file... + */ + + rewind(file); + + while ((bytes = fread(buffer, 1, sizeof(buffer), file)) > 0) + if (httpWrite(http, buffer, bytes) < bytes) + break; + } + + /* + * Get the server's return status... + */ + + DEBUG_puts("cupsDoFileRequest: update..."); + + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + + if (status == HTTP_UNAUTHORIZED) + { + DEBUG_puts("cupsDoFileRequest: unauthorized..."); + + /* + * Flush any error message... + */ + + httpFlush(http); + + if ((password = cupsGetPassword("Password:")) != NULL) + { + /* + * Got a password; send it to the server... + */ + + if (!password[0]) + break; + sprintf(plain, "%s:%s", cupsUser(), password); + httpEncode64(encode, plain); + sprintf(authstring, "Basic %s", encode); + + continue; + } + else + break; + } + + if (status != HTTP_OK) + { + DEBUG_printf(("cupsDoFileRequest: error %d...\n", status)); + + /* + * Flush any error message... + */ + + httpFlush(http); + break; + } + else + { + /* + * Read the response... + */ + + DEBUG_puts("cupsDoFileRequest: response..."); + + response = ippNew(); + + if (ippRead(http, response) == IPP_ERROR) + { + /* + * Delete the response... + */ + + ippDelete(response); + response = NULL; + + /* + * Flush any remaining data... + */ + + httpFlush(http); + break; + } + } + } + + /* + * Close the file if needed... + */ + + if (filename != NULL) + fclose(file); + + /* + * Delete the original request and return the response... + */ + + ippDelete(request); + + return (response); +} + + +/* + * 'cupsGetClasses()' - Get a list of printer classes. + */ + +int /* O - Number of classes */ +cupsGetClasses(char ***classes) /* O - Classes */ +{ + int n; /* Number of classes */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + return (0); + + /* + * Build a CUPS_GET_CLASSES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_CLASSES; + 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); + + /* + * Do the request and get back a response... + */ + + n = 0; + *classes = NULL; + + if ((response = cupsDoRequest(cups_server, request, "/classes/")) != NULL) + { + for (attr = response->attrs; attr != NULL; attr = attr->next) + if (strcmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + { + if (n == 0) + *classes = malloc(sizeof(char *)); + else + *classes = realloc(*classes, sizeof(char *) * (n + 1)); + + if (*classes == NULL) + { + ippDelete(response); + return (0); + } + + (*classes)[n] = strdup(attr->values[0].string.text); + n ++; + } + + ippDelete(response); + } + + return (n); +} + + +/* + * 'cupsGetDefault()' - Get the default printer or class. + */ + +const char * /* O - Default printer or NULL */ +cupsGetDefault(void) +{ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + static char def_printer[64];/* Default printer */ + + + /* + * First see if the LPDEST or PRINTER environment variables are + * set... + */ + + if (getenv("LPDEST") != NULL) + return (getenv("LPDEST")); + else if (getenv("PRINTER") != NULL) + return (getenv("PRINTER")); + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + return (NULL); + + /* + * Build a CUPS_GET_DEFAULT request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_DEFAULT; + 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); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(cups_server, request, "/printers/")) != NULL) + { + if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) + { + strcpy(def_printer, attr->values[0].string.text); + ippDelete(response); + return (def_printer); + } + + ippDelete(response); + } + + return (NULL); +} + + +/* + * 'cupsGetPPD()' - Get the PPD file for a printer. + */ + +const char * /* O - Filename for PPD file */ +cupsGetPPD(const char *name) /* I - Printer name */ +{ + FILE *fp; /* PPD file */ + int bytes; /* Number of bytes read */ + char buffer[8192]; /* Buffer for file */ + char printer[HTTP_MAX_URI], /* Printer name */ + hostname[HTTP_MAX_URI], /* Hostname */ + resource[HTTP_MAX_URI]; /* Resource name */ + static char filename[HTTP_MAX_URI]; /* Local filename */ + char *tempdir; /* Temporary file directory */ + + + /* + * See if we can connect to the server... + */ + + if (!cups_connect(name, printer, hostname)) + return (NULL); + + /* + * Then check for the cache file... + */ + +#if defined(WIN32) || defined(__EMX__) + tempdir = "C:/WINDOWS/TEMP"; + + sprintf(filename, "%s/%s.ppd", tempdir, printer); +#else + if ((tempdir = getenv("TMPDIR")) == NULL) + tempdir = "/tmp"; + + sprintf(filename, "%s/%d.%s.ppd", tempdir, getuid(), printer); +#endif /* WIN32 || __EMX__ */ + + /* + * And send a request to the HTTP server... + */ + + sprintf(resource, "/printers/%s.ppd", printer); + + httpClearFields(cups_server); + httpSetField(cups_server, HTTP_FIELD_HOST, hostname); + httpGet(cups_server, resource); + + switch (httpUpdate(cups_server)) + { + case HTTP_OK : /* New file - get it! */ + break; + default : + return (NULL); + } + + /* + * OK, we need to copy the file; open the file and copy it... + */ + + unlink(filename); + if ((fp = fopen(filename, "w")) == NULL) + { + /* + * Can't open file; close the server connection and return NULL... + */ + + httpClose(cups_server); + cups_server = NULL; + return (NULL); + } + + while ((bytes = httpRead(cups_server, buffer, sizeof(buffer))) > 0) + fwrite(buffer, bytes, 1, fp); + + fclose(fp); + + return (filename); +} + + +/* + * 'cupsGetPrinters()' - Get a list of printers. + */ + +int /* O - Number of printers */ +cupsGetPrinters(char ***printers) /* O - Printers */ +{ + int n; /* Number of printers */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + return (0); + + /* + * Build a CUPS_GET_PRINTERS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PRINTERS; + 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); + + /* + * Do the request and get back a response... + */ + + n = 0; + *printers = NULL; + + if ((response = cupsDoRequest(cups_server, request, "/printers/")) != NULL) + { + for (attr = response->attrs; attr != NULL; attr = attr->next) + if (strcmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + { + if (n == 0) + *printers = malloc(sizeof(char *)); + else + *printers = realloc(*printers, sizeof(char *) * (n + 1)); + + if (*printers == NULL) + { + ippDelete(response); + return (0); + } + + (*printers)[n] = strdup(attr->values[0].string.text); + n ++; + } + + ippDelete(response); + } + + return (n); +} + + +/* + * 'cupsPrintFile()' - Print a file to a printer or class. + */ + +int /* O - Job ID */ +cupsPrintFile(const char *name, /* I - Printer or class name */ + const char *filename, /* I - File to print */ + const char *title, /* I - Title of job */ + int num_options,/* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + int i; /* Looping var */ + int n, n2; /* Attribute values */ + char *option, /* Name of option */ + *val, /* Pointer to option value */ + *s; /* Pointer into option value */ + ipp_t *request; /* IPP request */ + ipp_t *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP job-id attribute */ + char hostname[HTTP_MAX_URI], /* Hostname */ + printer[HTTP_MAX_URI], /* Printer or class name */ + uri[HTTP_MAX_URI]; /* Printer URI */ + cups_lang_t *language; /* Language to use */ + int jobid; /* New job ID */ + + + DEBUG_printf(("cupsPrintFile(\'%s\', \'%s\', %d, %08x)\n", + printer, filename, num_options, options)); + + if (name == NULL || filename == NULL) + return (0); + + /* + * Setup a connection and request data... + */ + + if ((request = ippNew()) == NULL) + return (0); + + if (!cups_connect(name, printer, hostname)) + { + DEBUG_printf(("cupsPrintFile: Unable to open connection - %s.\n", + strerror(errno))); + ippDelete(request); + return (0); + } + + /* + * Build a standard CUPS URI for the printer and fill the standard IPP + * attributes... + */ + + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + + sprintf(uri, "ipp://%s:%d/printers/%s", hostname, ippPort(), printer); + + 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 != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Handle raw print files... + */ + + if (cupsGetOption("raw", num_options, options)) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/vnd.cups-raw"); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/octet-stream"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + if (title) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); + + /* + * Then add all options on the command-line... + */ + + for (i = 0; i < num_options; i ++) + { + /* + * Skip the "raw" option - handled above... + */ + + if (strcmp(options[i].name, "raw") == 0) + continue; + + /* + * See what the option value is; for compatibility with older interface + * scripts, we have to support single-argument options as well as + * option=value, option=low-high, and option=MxN. + */ + + option = options[i].name; + val = options[i].value; + + if (*val == '\0') + val = NULL; + + if (val != NULL) + { + if (strcasecmp(val, "true") == 0 || + strcasecmp(val, "on") == 0 || + strcasecmp(val, "yes") == 0) + { + /* + * Boolean value - true... + */ + + n = 1; + val = ""; + } + else if (strcasecmp(val, "false") == 0 || + strcasecmp(val, "off") == 0 || + strcasecmp(val, "no") == 0) + { + /* + * Boolean value - false... + */ + + n = 0; + val = ""; + } + + n = strtol(val, &s, 0); + } + else + { + if (strncmp(option, "no", 2) == 0) + { + option += 2; + n = 0; + } + else + n = 1; + + s = ""; + } + + if (*s != '\0' && *s != '-' && (*s != 'x' || s == val)) + { + /* + * String value(s)... + */ + + DEBUG_printf(("cupsPrintFile: Adding string option \'%s\' with value \'%s\'...\n", + option, val)); + + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val); + } + else if (val != NULL) + { + /* + * Numeric value, range, or resolution... + */ + + if (*s == '-') + { + n2 = strtol(s + 1, NULL, 0); + ippAddRange(request, IPP_TAG_JOB, option, n, n2); + + DEBUG_printf(("cupsPrintFile: Adding range option \'%s\' with value %d-%d...\n", + option, n, n2)); + } + else if (*s == 'x') + { + n2 = strtol(s + 1, &s, 0); + + if (strcmp(s, "dpc") == 0) + ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_CM, n, n2); + else if (strcmp(s, "dpi") == 0) + ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_INCH, n, n2); + else + ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, option, NULL, val); + + DEBUG_printf(("cupsPrintFile: Adding resolution option \'%s\' with value %s...\n", + option, val)); + } + else + { + ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, option, n); + + DEBUG_printf(("cupsPrintFile: Adding integer option \'%s\' with value %d...\n", + option, n)); + } + } + else + { + /* + * Boolean value... + */ + + DEBUG_printf(("cupsPrintFile: Adding boolean option \'%s\' with value %d...\n", + option, n)); + ippAddBoolean(request, IPP_TAG_JOB, option, (char)n); + } + } + + /* + * Try printing the file... + */ + + sprintf(uri, "/printers/%s", printer); + + if ((response = cupsDoFileRequest(cups_server, request, uri, filename)) == NULL) + jobid = 0; + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + DEBUG_printf(("IPP response code was 0x%x!\n", + response->request.status.status_code)); + jobid = 0; + } + else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) + { + DEBUG_puts("No job ID!"); + jobid = 0; + } + else + jobid = attr->values[0].integer; + + if (response != NULL) + ippDelete(response); + + return (jobid); +} + + +/* + * 'cupsTempFile()' - Generate a temporary filename. + */ + +char * /* O - Filename */ +cupsTempFile(char *filename, /* I - Pointer to buffer */ + int len) /* I - Size of buffer */ +{ + char *tmpdir; /* TMPDIR environment var */ + static char buf[1024] = ""; /* Buffer if you pass in NULL and 0 */ + + + /* + * See if a filename was specified... + */ + + if (filename == NULL) + { + filename = buf; + len = sizeof(buf); + } + + /* + * See if TMPDIR is defined... + */ + + if ((tmpdir = getenv("TMPDIR")) == NULL) + tmpdir = "/var/tmp"; + + if ((strlen(tmpdir) + 8) > len) + { + /* + * The specified directory exceeds the size of the buffer; default it... + */ + + strcpy(buf, "/var/tmp/XXXXXX"); + return (mktemp(buf)); + } + else + { + /* + * Make the temporary name using the specified directory... + */ + + sprintf(filename, "%s/XXXXXX", tmpdir); + return (mktemp(filename)); + } +} + + +/* + * 'cups_connect()' - Connect to the specified host... + */ + +static char * /* I - Printer name or NULL */ +cups_connect(const char *name, /* I - Destination (printer[@host]) */ + char *printer, /* O - Printer name */ + char *hostname) /* O - Hostname */ +{ + char hostbuf[HTTP_MAX_URI]; + /* Name of host */ + static char printerbuf[HTTP_MAX_URI]; + /* Name of printer or class */ + + + if (name == NULL) + return (NULL); + + if (sscanf(name, "%[^@]@%s", printerbuf, hostbuf) == 1) + strcpy(hostbuf, cupsServer()); + + if (hostname != NULL) + strcpy(hostname, hostbuf); + else + hostname = hostbuf; + + if (printer != NULL) + strcpy(printer, printerbuf); + else + printer = printerbuf; + + if (cups_server != NULL) + { + if (strcasecmp(cups_server->hostname, hostname) == 0) + return (printer); + + httpClose(cups_server); + } + + if ((cups_server = httpConnect(hostname, ippPort())) == NULL) + return (NULL); + else + return (printer); +} + + +/* + * End of "$Id$". + */ diff --git a/data/Makefile b/data/Makefile new file mode 100644 index 0000000000..b4c96b0e5d --- /dev/null +++ b/data/Makefile @@ -0,0 +1,56 @@ +# +# "$Id$" +# +# Datafile makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Data files... +# + +FILES = 8859-1 8859-14 8859-15 8859-2 8859-3 8859-4 8859-5 \ + 8859-6 8859-7 8859-8 8859-9 HPGLprolog + +# +# Make everything... +# + +all: + +# +# Clean all config and object files... +# + +clean: + +# +# Install files... +# + +install: + -$(MKDIR) $(DATADIR)/data + $(CP) $(FILES) $(DATADIR)/data + +# +# End of "$Id$". +# diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000000..7a59f9bcc0 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,109 @@ +# +# "$Id$" +# +# Documentation makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# HTMLDOC generation rules... +# + +.SUFFIXES: .html .pdf .shtml +.shtml.html: + echo Formatting $@... + htmldoc --title images/cups-large.gif --numbered -f $@ $< +.shtml.pdf: + echo Formatting $@... + htmldoc --title images/cups-large.gif --duplex --compression=9 \ + --numbered --jpeg -f $@ $< + +# +# Document files... +# + +DOCUMENTS = cmp.shtml idd.shtml sam.shtml sdd.shtml ssr.shtml \ + stp.shtml sum.shtml svd.shtml +DOCIMAGES = images/cups-block-diagram.gif images/cups-large.gif \ + images/cups-medium.gif images/cups-small.gif +WEBPAGES = cups.css cupsdoc.css index.html documentation.html +WEBIMAGES = images/classes.gif images/logo.gif images/navbar.gif \ + images/printer-idle.gif images/printer-processing.gif \ + images/printer-stopped.gif + +# +# +# Make all documents... +# + +all: $(DOCUMENTS:.shtml=.pdf) $(DOCUMENTS:.shtml=.html) overview.pdf + +# +# Remove all generated files... +# + +clean: + $(RM) $(DOCUMENTS:.shtml=.pdf) + $(RM) $(DOCUMENTS:.shtml=.html) + $(RM) overview.pdf + +# +# Install all documentation files... +# + +install: + -$(MKDIR) $(DATADIR)/doc + $(CP) $(WEBPAGES) $(DATADIR)/doc + $(CP) overview.html overview.pdf $(DATADIR)/doc + $(CP) $(DOCUMENTS:.shtml=.html) $(DATADIR)/doc + $(CP) $(DOCUMENTS:.shtml=.pdf) $(DATADIR)/doc + -$(MKDIR) $(DATADIR)/doc/images + $(CP) $(WEBIMAGES) $(DATADIR)/doc/images + $(CP) $(DOCIMAGES) $(DATADIR)/doc/images + +# +# The overview, admin guide, and user's guide get special attention... +# + +overview.pdf: overview.html + echo Formatting $@... + htmldoc --duplex --compression=9 --jpeg --webpage -f $@ $< + +sam.html: sam.shtml + echo Formatting $@... + htmldoc --title images/cups-large.gif -f $@ $< +sam.pdf: sam.shtml + echo Formatting $@... + htmldoc --title images/cups-large.gif --duplex --compression=9 \ + --jpeg -f $@ $< + +sum.html: sum.shtml + echo Formatting $@... + htmldoc --title images/cups-large.gif -f $@ $< +sum.pdf: sum.shtml + echo Formatting $@... + htmldoc --title images/cups-large.gif --duplex --compression=9 \ + --jpeg -f $@ $< + +# +# End of Makefile. +# diff --git a/doc/cmp.html b/doc/cmp.html new file mode 100644 index 0000000000..2ed695324d --- /dev/null +++ b/doc/cmp.html @@ -0,0 +1,651 @@ + + +CUPS Configuration Management Plan + + + + + +


+

CUPS Configuration Management Plan


+CUPS-CMP-1.0
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 File Management + +4 Trouble Report Processing + +5 Software Releases + +A Glossary + +B Coding Requirements + +C Software Trouble Report Form
+

1 Scope

+

1.1 Identification

+ This configuration management plan document provides the guidelines +for development and maintainance of the Common UNIX Printing System +("CUPS") Version 1.0 software. +

1.2 System Overview

+ The Common UNIX Printing System provides a portable printing layer for + UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

1.3 Document Overview

+ This configuration management document is organized into the following +sections: +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - File Management
  • +
  • 4 - Trouble Report Processing
  • +
  • 5 - Software Releases
  • +
  • A - Glossary
  • +
  • B - Coding Requirements
  • +
+

2 References

+

2.1 CUPS Documentation

+ The following CUPS documentation is referenced by this document: +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.0: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.0: CUPS Software Design Description
  • +
  • CUPS-SPM-1.0: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.0: CUPS Software Security Report
  • +
  • CUPS-STP-1.0: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.0.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+ The following non-CUPS documents are referenced by this document: +
    +
  • IEEE 1387.4, System Administration: Printing (draft)
  • +
  • IPP/1.0: Additional Optional Operations - Set 1
  • +
  • IPP/1.0: Encoding and Transport
  • +
  • IPP/1.0: Implementers Guide
  • +
  • IPP/1.0: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
+

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", "libcups", 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. +

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. +

Documentation on the CVS software is included with the whitepaper, +"CVS II: Parallelizing Software Development".

+

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: +
    +
  1. STR is closed with complete resolution
  2. +
  3. STR is closed without resolution
  4. +
  5. STR is active
  6. +
  7. STR is pending (new STR or additional information available)
  8. +
+ 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: +
    +
  1. Request for enhancement
  2. +
  3. Documentation error
  4. +
  5. Unable to print a file
  6. +
  7. Unable to print to a printer
  8. +
  9. Unable to print at all
  10. +
+ The scope of the problem should also be determined as: +
    +
  1. Specific to a machine
  2. +
  3. Specific to an operating system
  4. +
  5. Applies to all machines and operating systems
  6. +
+

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. +

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).

+

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. +

4.4 Notification

+ 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: +
    +
    +major.minor.patch
    +1.0.0
    +
    +
+ Beta-test releases are indentified by appending the letter B followed +by the build number: +
    +
    +major.minor.patchbbuild
    +1.0.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: +
    +
    +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: +
    +
    +1.0.0b1    First beta release
    +1.0.0b2    Second beta release
    +1.0.0      First production release
    +1.0.1b1    First beta of 1.0.1
    +1.0.1      Production release of 1.0.1
    +1.1.0b1    First beta of 1.1.0
    +1.1.0      Production release of 1.1.0
    +2.0.0b1    First beta of 2.0.0
    +2.0.0      Production release of 2.0.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. +

5.3 Testing

+ Software testing shall be conducted according to the CUPS Software +Test Plan, CUPS-STP-1.0. 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. +

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.
+
+

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 Printer 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
+
PCL
+
Page Control Language
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+

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. +

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 +".cpp" 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: cmp.shtml,v +1.3 1999/05/21 20:54:04 mike Exp $" tag: +
    +
    +/*
    + * "$Id$"
    + *
    + *   Description of file contents.
    + *
    + *   Copyright 1997-1999 by Easy Software Products, all rights
    + *   reserved.
    + *
    + *   These coded instructions, statements, and computer programs are
    + *   the property of Easy Software Products and are protected by
    + *   Federal copyright law.  Distribution and use rights are outlined
    + *   in the file "LICENSE.txt" which should have been included with
    + *   this file.  If this file is missing or damaged please contact
    + *   Easy Software Products at:
    + *
    + *       Attn: CUPS Licensing Information
    + *       Easy Software Products
    + *       44145 Airport View Drive, Suite 204
    + *       Hollywood, Maryland 20636-3111 USA
    + *
    + *       Voice: (301) 373-9603
    + *       EMail: cups-info@cups.org
    + *         WWW: http://www.cups.org
    + *
    + * Contents:
    + *
    + *   function1() - Description 1.
    + *   function2() - Description 2.
    + *   function3() - Description 3.
    + */
    +
    +
+ The bottom of each source file shall contain a trailer giving the name +of the file using the CVS "$Id: cmp.shtml,v 1.3 1999/05/21 20:54:04 +mike Exp $" 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: +
    +
    +/*
    + * End of "$Id$".
    + */
    +
    +
+

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.) +

Functions with a local scope shall be declared "static" and be +lowercase with underscores between words ("do_this", "do_that", +"do_something_else", 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: +
    +
    +/*
    + * 'do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +static float     /* O - Inverse power value, 0.0 <= y <= 1.0 */
    +do_this(float x) /* I - Power value (0.0 <= x <= 1.0) */
    +{
    + ...
    + return (y);
    +}
    +
    +
+

B.3 Methods

+

B.3.1 Naming

+ 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: +
    +
    +/*
    + * 'class::do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +float                   /* O - Inverse power value, 0.0 <= y <= 1.0 */
    +class::do_this(float x) /* I - Power value (0.0 <= x <= 1.0) */
    +{
    + ...
    + return (y);
    +}
    +
    +
+

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. +

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".

+

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: +
    +
    +int this_variable;   /* The current state of this */
    +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.) +

B.5.2 Documentation

+ Each type shall have a comment block immediately before the typedef: +
    +
    +/*
    + * This type is for CUPS foobar options.
    + */
    +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.) +

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: +
    +
    +/*
    + * This structure is for CUPS foobar options.
    + */
    +struct cups_this_struct_str
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+

B.7 Classes

+

B.7.1 Naming

+ 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: +
    +
    +/*
    + * This class is for CUPS foobar options.
    + */
    +class cups_this_class
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+

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.) +

Typed enumerations shall be used whenever possible to allow for type +checking by the compiler.

+

B.8.2 Documentation

+ Comment blocks shall immediately follow each constant: +
    +
    +enum
    +{
    +  CUPS_THIS_TRAY,   /* This tray */
    +  CUPS_THAT_TRAY    /* That tray */
    +};
    +
    +
+

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: +
    +
    +/*
    + * Clear the state array before we begin...
    + */
    +
    +for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +  array[i] = STATE_IDLE;
    +
    +/*
    + * Wait for state changes...
    + */
    +
    +do
    +{
    +  for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +    if (array[i] != STATE_IDLE)
    +      break;
    +
    +  if (i == (sizeof(array) / sizeof(array[0])))
    +    sleep(1);
    +} while (i == (sizeof(array) / sizeof(array[0])));
    +
    +
+

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: +
    +
    +{
    +  int i; /* Looping var */
    +
    + /*
    +  * Process foobar values from 0 to 999...
    +  */
    +
    +  for (i = 0; i < 1000; i ++)
    +  {
    +    do_this(i);
    +    do_that(i);
    +  }
    +}
    +
    +
+ 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])
    +{
    +  case STATE_IDLE :
    +      do_this(i);
    +      do_that(i);
    +      break;
    +  default :
    +      do_nothing(i);
    +      break;
    +}
    +
    +
+

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. +

B.9.2.c Return Values

+ 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: +
    +
    +for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
    +  array[i] = STATE_IDLE;
    +
    +
+

C Software Trouble Report Form

+
+ + + + + +
Summary of Problem: +________________________________________
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
Detailed Description of Problem: +________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________
+
+ + diff --git a/doc/cmp.pdf b/doc/cmp.pdf new file mode 100644 index 0000000000..95d7b965d0 --- /dev/null +++ b/doc/cmp.pdf @@ -0,0 +1,963 @@ +%PDF-1.2 +%âãÏÓ +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +4 0 obj<>endobj +5 0 obj<>endobj +6 0 obj<>endobj +7 0 obj<>endobj +8 0 obj<>endobj +9 0 obj<>endobj +10 0 obj<>endobj +11 0 obj<>endobj +12 0 obj<>endobj +13 0 obj<>endobj +14 0 obj<>endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj<>endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj<>endobj +22 0 obj<>endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj<>endobj +26 0 obj<>endobj +27 0 obj<>endobj +28 0 obj<>endobj +29 0 obj<>endobj +30 0 obj<>endobj +31 0 obj<>endobj +32 0 obj<>endobj +33 0 obj<>endobj +34 0 obj<>endobj +35 0 obj<>endobj +36 0 obj<>endobj +37 0 obj<>endobj +38 0 obj<>endobj +39 0 obj<>endobj +40 0 obj<>endobj +41 0 obj<>endobj +42 0 obj<>endobj +43 0 obj<>endobj +44 0 obj<>endobj +45 0 obj<>endobj +46 0 obj<>endobj +47 0 obj<>endobj +48 0 obj<>endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj<>endobj +52 0 obj<>endobj +53 0 obj<>endobj +54 0 obj<>endobj +55 0 obj<>endobj +56 0 obj<>endobj +57 0 obj<>endobj +58 0 obj<>endobj +59 0 obj<>endobj +60 0 obj<>endobj +61 0 obj<>endobj +62 0 obj<>endobj +63 0 obj<>endobj +64 0 obj<>endobj +65 0 obj<>endobj +66 0 obj<>endobj +67 0 obj<>endobj +68 0 obj<>endobj +69 0 obj<>endobj +70 0 obj<>endobj +71 0 obj<>endobj +72 0 obj<>endobj +73 0 obj<>endobj +74 0 obj<>endobj +75 0 obj<>endobj +76 0 obj<>endobj +77 0 obj<>endobj +78 0 obj<>endobj +79 0 obj<>endobj +80 0 obj<>endobj +81 0 obj<>endobj +82 0 obj<>endobj +83 0 obj<>endobj +84 0 obj<>endobj +85 0 obj<>endobj +86 0 obj<>endobj +87 0 obj<>endobj +88 0 obj<>endobj +89 0 obj<>endobj +90 0 obj<>endobj +91 0 obj<>endobj +92 0 obj<>endobj +93 0 obj<>endobj +94 0 obj<>endobj +95 0 obj<>endobj +96 0 obj<>endobj +97 0 obj<>endobj +98 0 obj<>endobj +99 0 obj<>endobj +100 0 obj<>endobj +101 0 obj<>endobj +102 0 obj<>endobj +103 0 obj<>endobj +104 0 obj<>endobj +105 0 obj<>endobj +106 0 obj[10 0 R +11 0 R +12 0 R +13 0 R +14 0 R +15 0 R +16 0 R +17 0 R +18 0 R +19 0 R +20 0 R +21 0 R +22 0 R +23 0 R +24 0 R +25 0 R +26 0 R +27 0 R +28 0 R +29 0 R +30 0 R +31 0 R +32 0 R +33 0 R +34 0 R +35 0 R +36 0 R +37 0 R +38 0 R +39 0 R +40 0 R +41 0 R +42 0 R +43 0 R +44 0 R +45 0 R +46 0 R +47 0 R +48 0 R +49 0 R +50 0 R +51 0 R +52 0 R +53 0 R +54 0 R +55 0 R +56 0 R +57 0 R +58 0 R +59 0 R +60 0 R +61 0 R +62 0 R +63 0 R +64 0 R +65 0 R +66 0 R +67 0 R +68 0 R +69 0 R +70 0 R +71 0 R +72 0 R +73 0 R +74 0 R +75 0 R +76 0 R +77 0 R +78 0 R +79 0 R +80 0 R +81 0 R +82 0 R +83 0 R +84 0 R +85 0 R +86 0 R +87 0 R +88 0 R +89 0 R +90 0 R +91 0 R +92 0 R +93 0 R +94 0 R +95 0 R +96 0 R +97 0 R +98 0 R +99 0 R +100 0 R +101 0 R +102 0 R +103 0 R +104 0 R +105 0 R +]endobj +107 0 obj<>endobj +108 0 obj<>endobj +109 0 obj<>endobj +110 0 obj<>endobj +111 0 obj<>endobj +112 0 obj<>endobj +113 0 obj<>endobj +114 0 obj<>endobj +115 0 obj<>endobj +116 0 obj<>endobj +117 0 obj<>endobj +118 0 obj<>endobj +119 0 obj<>endobj +120 0 obj<>endobj +121 0 obj<>endobj +122 0 obj<>endobj +123 0 obj<>endobj +124 0 obj<>endobj +125 0 obj<>endobj +126 0 obj<>endobj +127 0 obj<>endobj +128 0 obj<>endobj +129 0 obj<>endobj +130 0 obj<>endobj +131 0 obj<>endobj +132 0 obj<>endobj +133 0 obj<>endobj +134 0 obj[107 0 R +108 0 R +109 0 R +110 0 R +111 0 R +112 0 R +113 0 R +114 0 R +115 0 R +116 0 R +117 0 R +118 0 R +119 0 R +120 0 R +121 0 R +122 0 R +123 0 R +124 0 R +125 0 R +126 0 R +127 0 R +128 0 R +129 0 R +130 0 R +131 0 R +132 0 R +133 0 R +]endobj +135 0 obj<>endobj +136 0 obj<>endobj +137 0 obj<>endobj +138 0 obj<>endobj +139 0 obj<>endobj +140 0 obj<>endobj +141 0 obj<>endobj +142 0 obj<>endobj +143 0 obj<>endobj +144 0 obj<>endobj +145 0 obj<>endobj +146 0 obj<>endobj +147 0 obj<>endobj +148 0 obj<>endobj +149 0 obj<>endobj +150 0 obj<>endobj +151 0 obj<>endobj +152 0 obj<>endobj +153 0 obj<>endobj +154 0 obj<>endobj +155 0 obj<>endobj +156 0 obj<>endobj +157 0 obj<>endobj +158 0 obj<>endobj +159 0 obj<>endobj +160 0 obj<>endobj +161 0 obj<>endobj +162 0 obj<>endobj +163 0 obj<>endobj +164 0 obj<>endobj +165 0 obj<>endobj +166 0 obj<>endobj +167 0 obj<>endobj +168 0 obj<>endobj +169 0 obj<>endobj +170 0 obj<>endobj +171 0 obj<>endobj +172 0 obj<>endobj +173 0 obj<>endobj +174 0 obj<>endobj +175 0 obj<>endobj +176 0 obj<>endobj +177 0 obj<>endobj +178 0 obj<>endobj +179 0 obj<>endobj +180 0 obj<>endobj +181 0 obj<>endobj +182 0 obj<>endobj +183 0 obj<>endobj +184 0 obj<>endobj +185 0 obj<>endobj +186 0 obj<>endobj +187 0 obj<>endobj +188 0 obj<>endobj +189 0 obj<>endobj +190 0 obj<>endobj +191 0 obj<>endobj +192 0 obj<>>>>>endobj +193 0 obj<>stream +xÚíßoÜ8’Ç¥nõKždOún§;àâ´wfŠmí](IîápÁNfn³3·™Ìö¿¿þåný ¥ª"%Q^s€Aân~ÄⷊdQý××bµùïZ|{#Þ¾þˋ;ù"–/þ*Þ®¾»úv÷oß½»Z‰ïÞ_݈››ë«Û]­oî³ÿ|óñMúowbý¯«]y»+ïvåý®ÜïÊwåÿõæ£øúå÷ÏoþCܾ½~óïb}}ýæîÅ­øøð"šž¹ÌŠ|¸Y,gÛ²ùÃâöaì\ò~qzªrv~ù0N.ys¡F*À-nGÆ%oژËùe<.<Ôív \÷¹ø‹Øq®»Ðã•óµÃ\7\*›æΌ•Ý1³Ìu/<óòMìWváY)þ¥S\7žµ2Y;Ã%…g³\:Âe¬v‡Ì—¼ð¬ÿÕà\YèuQ¾˜ëÎë¨Lâ!¹®½ÎŠ¿ŒË²Z·±6åÕ \2ô<ÁÀI!,——½sõ‚Ń`qÀ` X 0pZ2øâãÀò¼eO\û-3Íæêk÷Áµòz/“¸>x”iç\©7HyÙ1WÃEEp_áYÚcB†vÀH4ƒ:Åè\™7hYwÅ˅œb0‡Ìñb0ÏE{"—Ëó;àpyu®Ôs¢¬-sÉÐ ®‰e®•çH™[åJ=gJl‘Ë+D91Wä9TÖÖ¸2—°Z¥Æ'¨¨F(˜¨Fiàµ˕¸†Õ2`0>G ŒPã1ÎÇ%]ÄjŒëaŒ˜a0>—ŒšaÐßp/¯¶ån{ñ¡Ûƒ^†Ë?UŸäÛ{ t?\~CÒ¿¼¿èfÀ ëá:o]*Ý - ¸VÝ UqÔÖÃzèp¸éǒ›¼fs±C Zº8“lÊåâ†ôô܌µdˆ™\Ìáb¥Ss†,`r±yn6$cÈ|Wҍ¶[²%‹+ìˏÞ,´"õ`WÃ$흓l°fp‰Þ¦?ó* se`‘Á|:Yä};W$…±r4s „E›R¹’ŒcŠ1‘K …E›Ó¸2+’ ¹0°·ðz™[-©‘!‚µHÞ2éö՜•XgŒÊÊàÃÁ’jø±}.Bb<—4ÒLKÆ7D= :¹öåÛÁÊ +e’wT×Á†Ìv2¹h“aŽåІrÈ5WÂZ¥¶†ˆ³WF6Ãf®´„S㒬͒§k@”IŽç’f¡æ:ši³$Ãõˆkå€Àµëx çJX{v8¡¢l,)\pø —díÙµö²ÆÅH_læÊ¢ á:t‘¸g¡º4٘ä®ü ô:.à8%(“šlÌh\¥×qEœñJQžh²±¤q”^Çræ—D={ࢸJ¯áJyg!F²mLˆ\¥×pE¼Íþ¶ç?-sIÆôjåÚ+½†+äÎD˜‡$ÙXR¹öJ¯æÊ˜§ Æ1io#§rí•^Íz30‹¤Ê\czµsí”^Í%˜™;㘁Et®uGúuå‚aˆm·.q±•˱•‚k×{¡âÚÛ½d„ÑM DQ±úÑÅEñË\§NT¹Ä^“ÝWˆ€XYe®eñÑT¹@Ãõ8P„Óì6̬ȅس™jLb^TÔI…+Óp%žŒnˆ B€ ‡sILë©îÖ¹V}Z‰ö´%.Á‘ÒѰ,ø¢W¤ä’ǬȆ(v„èPkA`YåJ•\ɱrB}:øèp¢÷ýÛWÚ\5³æ§ª\«£ÆHz¾UˆçÊ8^ùôþY^W”¹ +¿Qc_Ñ >:œc|ɬΕ(¸Š©(ÙWíðr¸ÆhS\çÊ\E½Iɋ0Às­X²Q³‰i^ç:Øj‰+,NXò"L>4——`ÉFuboï)ÖÅE®rFÔªƒŒF §ŠUÊ•‡Sìc¹¢’a'¤þZµ‹¿Ó{M^åJ.Yã +K–—uª è¨Wo'ÙîŧþyWH©\ SË~²ºÇÕÍûù¨ +`e~2J.Á‹¢œç +yQ”ë\ÒDæÊ åÐU®”:Ε<59wàoÚ¨íU—›Zéâ’õTp%u•”[ž`¹¦šðe©â +8\‚+¬?FË\{ƒÕåÎUº8ápMê\¢áŸ…G»”[Ð\K5—¯âª^çCqÕîå|ëOîÃÙà¸f\»?Ý ¯ÔƒYÙ±Ä*®¹Ò•ãQD£¢“yW½Q¤t°€ £‚ÜDÃcÎm¹‹õë|®z#¡tD(®Š+Uû¯TG)®ó!¸ê´\©%®HoܟJë×ù\õF¡Ò¡¸æ.éÕ¹q¢¸Î‡áª5Òr%ü0ªÐ‡ÃW4.ÑëJÅu> W­Q±úéQ\ëÜpý5Wv±vÃUk¤å~•«F³«ZëâA´i\ÕF\9š+Pýԏ5]¬^çCqUi¹"‹\kõ(Æê.V¯ó¡¸ª´\+~x˜« N³½_ëbõ:Š«Ú(¬¤©¹„5.?ÖpBÕR+×ùp\•F|® ’Ë_~zðˇm¹º‹•ë|8®J#QPìWh‡«XŒ7öہº‹•ë|8®J£Z•`¹‚·NÉU\…÷C)º¸m*W¹ÑªE.¯[®´‰«|É¥¸Xìâ +Ë53âÊtñü1¨D®r£¤:UÂ=—ì˜Kjnq(®ó!¹ÊÒŠdKË57âʹ€ÃUj$+¡yâWÆá*7 +ËL¸Ús—r•®óa¹Ê"E2þ†+–+âp•%§SåÓ&ïà\)‡«ÔH{™㠓e¥.Éá*7§ó¯;ÀwÉU¼Î‡æ*7Jjç•.p%®r£J$(v\&ËeWØÌ•q¸ÊÊ+ã`åWá:ž«Ò¨4`qÔ#×ZßňÃUnTN#‚Wëö†oÈ%¼âíLðS¹*>‹I?\Ç7hº(9\ÕFw…­ \î”û]þá7§÷Ï·r%Vï Bû6Ûèr{÷\â™ë™k \Ó'ÊŒ“+|æzæzæzæzæÂq͞¹ž¹ºçò̹6+ô½RJÝa¹îvï0ó/1Ý¥Ô˜ë¢z}­ü²¡ÂæuÕ§ê“*OqQJÛ;c.QKß(ç鏧êu\ëòfhG\ê+šò˼²ÓaÇ̍ªV®eùvÃ%'Jå&Ç-~‰ºyÔÊ5ïƒ TKkQœ`•ôJ]×,/MÍn¸BÕQçAXJ“©ÖepeKé„+{º®äxP(¯ ZÀSv…².Ÿ+í’+*œX¯NÞ¥à²NÉ皺ªm~õ§–w’.¹DA äiV4°ðBfM]—<>ÝLâIg\aqNT”þdööU2˲+Ör5Õ¥pmLp’öO;á*»WhÝìÔÕ¥pm$ÃO÷ŽÑ+Æí¶p5Õ¥pmG:ñŽ/ªëŒkR²-¿‘KW—Âû˰~—ɽQúgѨóMu)\ÉþfÍĜkÙ¼üš×!S-WS] +Wzrêq%Åñ\U>¦ÒÙ¦º®ì´hä2¹‡¸oëߞµ–Z®¦º-ñ|ém[²|*hÀ5o=‡=Bê‹Mu)\…÷ÂvÇ5¬Õª\ uI\Çet/;k¨Zåj¨ËàŠÍ¹f¸t›jè_‹UôuI\Qí'pez…©qeÜý¨2ŸJ#—Ñû7Ê{1/óF.}]—îý¬v¹ +½Ì[¸´uI\éѧ7smdo½ÑE¨=(1©kT ßÛs(”¯×ëç«ø ß³äl1|/Ö3Wÿ\í¯['Wôˏ’«}ƒc=J.“ó3Wÿ\F ËQsÍFÉ%ÿa¹‚Qrµ/À¦O”k2N®ð ¾†ßÇñÌ5×ê ¾¸ïñYŽ’ ž(WòDÃï5ª´½ìunø=tC•¶./qßè\ •Øár.j“ºØð{9‡*Š+]ÀÑJ`¿÷Öµ€C´Ùò{Š]Ûi Ûôù½Ò®Š ÆpÈV‹ü~sÇŽÇ5ºï£OZ‡0іsŽZ§ `ÌÕ9Ǽj•9ÀȋsL´º%À¸çXØ: +€âẃµ‡}€²WÇXÖ®€ÒÇV–i»zÊ8æÀ’öÎê8æÀ¢vã”Á:¶[µG}€Š#s`¢]ä'œn =¢¯€stN }†°-À¬SBŸ"´p +ã”Ð"H\U§„>BtCë’Ð „ir*ºчíîë‘KŽHè%Fº!Ç +ýl4r¸,p‰ñb‚™1€ ¹Ä£pc…Þ‹úE®t<‚ˆ2,ÈÑBïH„˜¡">ÈÑBŒDgE.„Ð;"€²+ÈÑBïˆp¬P:hõtE8BÄê«À•Œ$’j‚ýQäx¡F!“2Bè'£ Ì…غñG!³ +—‡p„8üƒp"âÈ‡xÃuB8R¤—B „#Bör‚ :°™ÝªÓ*BðÌØí +È)‚8sz-k\Ñ&ú.(öCéÑw­!' ÇÐ ýŽÈIÂ1ðkôS—p~‚áï€d¼CO°z¢@NŽa'>r’sx‚¥ø¥bå'áôH*:pˆH8‡œ(N0Ê!ÐÆyÐ5å ˆ ‡Ü䈝¢Ž¹ÉAÙjâÄPé3Ê$âH¨ô¤i 6Né¥k@UÒÁvÛ$IӀ:53D„-Mµ\+w ‘¶ý9}‚Í5Ãb,d—>!&4Cò +g C\ў7ЭxC”ÄÐÈKœa 1!>nÈl€Q§äœ ¸h†¥•pLÿ‹•„ú°!çL°ÞW͂ªf³&XÏI–)Ùû@Κ`=»°ˆ<7€5ä=+‡¤÷XS´gå`D­ÀYn÷súÌÎöHÏ1GÊ0 àMÒ^¥~ŘðÀ|<=J½äR°0qí{±;ÂçT®„4`6µƒ¢Y™KzÉÐ|€#· &……Kæ`1 "Íë9ƒ‹ö ›òMÏRØꀅ݅‚U˜«âµëU‹`4,}<Vö +îdÝ'–^ªÀV”v{Փ6ƒEm2U2VÃm4°çùOÖÁ³Å,¤~PÀæÊCXõ›ÎQå†þ1k>WÂâòü[ê`1,¾)hãb˜çÇVóÚ¨•+ò¸ÿ¥ó÷‚5s.éñË9ʳ Þo_q Øvž]¶™ã=“ªeùÐÎe2`{´ýï¾ Ù¿wnÈE]†) òò¡6nò~š<®Ü”+ó씳óÅbñêaSî‹‹Ðð·Í¹l ˜õҖÿˆá’rÍ-p™Iâ ÅãroÀ–V¸œ°ö­/—Ûp!¹§6}Ć’+]âZÛãJÇ5\h.ÖNGGÛäʜášç6¹œÑzÜñžK†cÑxw gÑ q9!Øó^ +—Ò¸°DôÑ!‰kpKÄgи²‘X!•kàø—p€MäÔ)¹/T®!½3åø‰Ê5``OJš#s 6Åhi/t®¦1±ŒÁ5Ì#ží2¸™bÔ,%=pÍ`sõ®ôT9WÏÚÁÈdrIᮚpõ)ЬÔa.W`¼L26#í§ÇeÌÕÓbŒyãÀ€«ÿìs/R˜puoŠü,M#®®Á ’O͸ºUE“daC®.´Q´)Ww`fÉøÆ\äêŽ&ö¹ºX¶¦«Ûá²/‹æ÷&¬påÒ®-^š÷Èׯí Ùd»Ã•Ë wË&—¥!;_ç®qåòÆX_Ùê‹M.~jõêÒ^Oìr¤W#R·‡äâ’٥ꂋCvþÊvºà"æÅû‹ÞsÑ ×¦<à²ãýóÛN>¾3®Ý¨µäÙâ¡«Ïî’k7l7‹3õ8]>tù¹]sín{Ãaqq¶-ç‹ÅåÃCçÙ ×â/’wòś?¾×ï…üA¼ûîê[q»ººòûºÏ!÷¿þòÃO?þþåÓן~ýEüéÓ/Ÿ~üü—Ï¿|ðó§_þYþϦñ­¸¾Þ6¾~ûîê­x}ýöêæ±ùëû?Áëë«Õ¶âëëÛ«kñúæÝþ·ÇŸ~û»È~ýáëÿ}úòYÀ—_¿ÿýÏ_ÛU¼}{õ®ð{~ýß¿ùéÇÿþºéãûo_oþ÷þ_ćŸéö‡¿‰ôóoŸ¿üíó÷Û¦±Üý?ÚiñÜendstream +endobj +194 0 obj +6320 +endobj +195 0 obj<>>>>>endobj +196 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +197 0 obj +31 +endobj +198 0 obj<>>>>>endobj +199 0 obj<>stream +xڕUMo"9½ó+J9%ÒЛB`oC¾„4™aŒöÀŸ«Á·«c»Aì¯ß²» E‹¢Hi»ªÞ{õʕ·V +×ü“Âmº}Ek4oýñ8„tóœoú·=˜g—)Ì$•x5ÿUßÞ$ƒú¾}3Hêˆ$…q†Æ«\Iá™:¸iڄvúuè|­H2¹ZU6†B!ŒXaÁéPja #YÕ_–6*C~°ªøO­ æd!à j*cœ0QÆó¯0ò€Ï¨i7éÔPàŽŠ‚Ñ^¾ÿ†‰åheV0Û9,./î^&³‹ÅüDë«4¹G¹ß +‹É íÝá^{g_åÇíFáöñŸÓx, $ëÅR#Ÿ51ZìÐFí!wѹé»zȗ.p Œ=¬…;’¿D4ûŽaË<·ƒY#yPVIύ¦À¡ LÁyn¬°Ù‚#]EË ¡u­bƒ&#ë‚ G¸•ãf&Zû»™ÞŸÑºÚWÔ¸ã±(x²vpm.$º¤©ºïb,Ç¥ëRãgКÉj_]¸ß/´ÿ± >ێƒÈ®„‰ÍaG;'­iß)ÆépÖ@²ê Xø;Ö¢Ó¿…ß™ðªo\öòÀpß´SY\¦˜#ÛÀÏõ¬Ô.§>†Ö?¿Ë<+¿ÇùsKUؔSŒ&ñógaÌϪt¤ïâ”÷ÓyZ¾r…'Müìíî¬Ä'ÞQœ›â[¥lìC>h¢Úµ{éà:9þ¯Üã³!ƒ„Óðý0oýÕú‰ßksendstream +endobj +200 0 obj +869 +endobj +201 0 obj<>>>>>endobj +202 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041׳P072PIÑp VpÎÏKËL/-J,ÉÌÏSðMÌKLOÍMÍ+QÈIÌÓ Éâ҅èхj2‰™˜˜é™)€ù† +ÁÉù© Q×®@.Nu!^endstream +endobj +203 0 obj +117 +endobj +204 0 obj<>>>>>endobj +205 0 obj<>stream +xÚ­•OÚ0Åï|Š9²Ò&K 7 +l…T´) {ââÆp•ØÔ6Úòíkc•V%]å@Æ¿7ö¼?ZtÌÀ „nòªõ)k=½ÄĐæMЃŒ¶CX`yŽê!ûîJžýÈyϑïÊüÆË$…‰ÈwrM4Ü-èAËþ+Ï6…(KñÎøÚ-¤— )µ.…o{ÐóU]3tàü#?<³Wa×Êm«àç‰ø¡Ó ^°õN:½9ád– IIø5ß4tÄßà³Éäžî•Æ +f\£,HŽ0AÅÖÜÞrɶ糹G"Í­„ÿ³…~'aD+ƙÒf/B*»—)ð¯·PÓ?¤õd~ H±–¤ª¬ w.n¡SÌw’é½±ïVH݀›%·¸ª¦I—˜ßRáÿŒímrûf¨ÖÛ¿Mîœ`ÏE§×)áUoPžb¬þ1Â\pï*Æ +l ™áÙt:…  üÞc° ç›Ý ¡×¶ŸU›JRèÕÃ]ç9K’§ÃÌG”2K$%¼nOèdxÆ^‚fì)ϵ=N!“„«» zbͪmyøÕ²ú¼c›qæ‚byh(Ŋ˜#ÌÕ] ÅËØ<âGøÂ8º1X¬ŒM̵ÈÅÑÛÑqÑÑ{aßúŸéE?6²æU×~žf­¯­_Ð&Ùûendstream +endobj +206 0 obj +522 +endobj +207 0 obj<>>>>>endobj +208 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041׳P072PIÑp VpÎÏKËL/-J,ÉÌÏSðMÌKLOÍMÍ+QÈIÌÓ Éâ҅èхj2‰™ê™)€ùF +A©i©E©yɩŠ)×®@.Z#bendstream +endobj +209 0 obj +122 +endobj +210 0 obj<>>>>>endobj +211 0 obj<>stream +xڍ“Mo›@†ïþ#N‰äÐ`üÙ['’­ÚB­rY/l»ì’ý¨“þúÎ.’›T•9xÅ;ûÎ<ïð4Iàš~ ¬f.7“›|òî~Éò’Þ,Wsȋ‹î…DøÈ«°Aå.óï½n¯{åÕb÷Ú8­0ȝ6/9ã¹óûŠ9$É Ÿ-{ýã5Xí G(ƒ‹­™”p@h%ãXëWş+¹6m«U!TNƒ«©H—îÈ vZûb6 Ý"µª,©‚?¹&i< ®‘å5^¢‰¦Iqྵô/!×`°aB‘_Ó2'ÔÚQ¸´,ÐÀ·O»‡®ßÞÌNaìP±í0‡ÒîÌŸ9ÒX ñ®™aÜ¡±@>Uåêø´éæ„vYO*äaßdš8íȳÐ܇ðSU@©MÃ\w²P åFè@|h[$ºÏp3…[ÝaþŠOžæ åöß-¦T¢JQyCдúkiþ»Ý!~¯î1×Ê-A—Ý‘l¸§UPö„¼,d}ò”îí>‹(ÆÓ^ĸ³,Î,#Z þ£ƒõacØNÊIUaÇȗ9hI)x7žÎT(u”$UƃÁi´íÀ¼gAO×ù>V„ð¹ôÙv–Aq¬…Öµhh7ƒ|·{Ÿi[¤D)~…D²á‚³‰¶ø“v¾ žÑÔz$ž®N_ék_ô|}oHFïá|—O¾L~•BN‰endstream +endobj +212 0 obj +542 +endobj +213 0 obj<>>>>>endobj +214 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041׳P072PIÑp VpÎÏKËL/-J,ÉÌÏSðMÌKLOÍMÍ+QÈIÌÓ Éâ҅èхj2‰[éY*€ùÆ +n™9©HAò®!\\»Þ% +endstream +endobj +215 0 obj +118 +endobj +216 0 obj<>>>>>endobj +217 0 obj<>stream +xڅVMsÛ8 ½ûW`zrfmý‘÷–¦»3=µ›¸³_h ŠØ¡H•¤ìæßï%Û±R¥“ÄÑð<<€þ9™ÑüÌèfN‹kÊëɧõä¯V4[Ѻěë›%­‹)>¼k·†éç#}ó.ç´}ºXÿ€Ç’f³Îãr~%Ÿ;zteÜ+ÏCçÍôÝãúáÝæ‚B¥Œ¡-Sh·µŽ‘ âûgŠºfRÔöä<íØøÇ¿öš-Bãeã@kIag‹l.a÷:V+¦ûïß)ô)dÇ|ÊþÈ«VÚFü!¬¶@,TT[˜ˆ³L®LX¥3ÆíQ-…¨"‡t~u*v–‘<š¢.ҁrã@LîêÆp”ÈÁ™6jg)ÏG]ÇÝçn*zÇ›å¹M¥ŠÍÔòžä!XUE¡^°P:_+¹#µSÚ(P¶¹ˆË—åÉ<ö±étô[Ç+ò¸ Y§hì*»í5³Xu¸ËlF÷FAX¥ÎÕ¡æßÊ뿊¥eñ,©ÑsÎ -T·!JZy‰§*þ¾±Â3ã}àŸ-¬ÚJAƒ5Û8ÒÉÏ.oåuÇ${ïüHó¾[¡˜¢u#**µëâЪ»ä!þÕ>~yÝPpr×‰é‡ u­k&8!²€}&F½1 çÒÁ.ÁZå<ÆDÿÒÖRð`MÄò ¹Ô#´Ý5ÑØâåõ!0¶x†‚K•Ÿ$7§/zõgÉ}EÓ9I+)Ög¯µø‚.18l#Yw—]r›iÀÔvçÌî°1`:(ûÐ ñ=ab©UR«çÀËYÆÞ©[Û×t®T¨±_°ÔޛڍÊ0²ÞôlSc¥U +ùmfº§›‹÷Òr¶O¨Yí5ZèXc‚Ì1nOÜÁÁ°àb§té뾌îøðYíYfv€óöZнóØ#oªádÒ&!¯¸h âÉ‚ظž9Òt|N‚éNƒ_r{>i%y‰š»±•q5ÝÅ3ˆ*Ð]‘ÐW}àJ…£ZØE º”‚Ì]_Y_GÏõí‰ÂÕBHÿã׊åí‡l{XÞÈýßëÉ¿“ÿóÇÞendstream +endobj +218 0 obj +873 +endobj +219 0 obj<>>>>>endobj +220 0 obj<>stream +xÚuÁNÃ0DïþŠ9–CLŒ“^©à*Â|€Û­Qbƒ“¶ð÷¬®È+YÚy³;ûÅjzwªT?²ÍnŸ¶÷¼ƒö¤©¶å +Ún$—xIsð¡7sHñF*!Ä +V"‚@}r8O.#e\\´ô… q±:‹ëÉEÌÄøð]s1a0‡Á>øEú̉#®fBoh˜ÅágêrN™¯Ë»¿åB¶Wu%³ÝìÞ÷oØ¥èÃñœ—¨x6ÑÝèâŒý`–èÕjªÚ¦.¦®ô¤¼Aýßµš½²_¿Yçendstream +endobj +221 0 obj +216 +endobj +222 0 obj<>>>>>endobj +223 0 obj<>stream +xڝVMSÛ0½çWìpjgˆ'’Þ€N/”¤\Y^'flɕd(ÿ¾»’çchÃ!±õôöí7¿1Œè/†«1L¦ ËÁÍjðå~ñVL¯.`•~º„¥ÎÜ«0X °h?¯žò2šìðrtÃ#›k?ê2A“«uÀ_@7èñ4 o-–P#pƒ8¬„qðÒ(Oé­p˜Bò1êԂÓ`°2hQ9º‹PŠgmΡÌ •B%œÜʋf d9žDc¶¨í× ms~q ¶öFÌž=òä‘çÝ9£Q4ÚõrÈT­Ÿ7èÄСu­r˜â™«”ÔçY\U…*¥xy +tŽœ¿L…~ >Hê¼H›Øü¿þÄÓì{‘Ä'ü¸†ÛÇ%X%*»Ñr kTr“iH™{ƒ„¼õ Èr%ŠÖeÿÆçšè¥˜)1ÝúØKVг—3Oòš»'IQæ%Y¨t®œåz(„ $5…ÖX©©@>£—øiôÔ ÷òDLî™ÜµF%QòÆqMg¢.(LŠ~Ú¶‰l í›uXҁ4X"kgwv굉Lß3ºø{aYæíðÝ-}Š6_+Ðøæ¢3ڃSß#§H¥«BÁãï©9Ø=ÀÝç¸G^¦7H5!uYQʰx#DЃi×£ÿ ¢g6ø°×Ú ‘}§çÃ9ojèsŸjP_¼=¯ß!nj\¢Ô$â4 #­ŒNké¸àáã=”B° ԋ=ÒcWâ.zh¦Ö.ô4{ÿÊø` :ngâ.ôû¸£ÝrñÍ6™·ëe ßÂÈ¡»G÷Êvcmǭ݈Pe½ÅÍkk)ÑÚ¬.¨bÛâM»–rF×IÁd•6.‚kbÒÉ3õ×b¯FñÊÚ ÆgyñÞrЁ·¢f¸Ji•‘†’>ŠšQ~´Ó*[›fžX]Ù²§X$=¦ÑM܅j+Z9§öï6N.;±\à” nEI-l%í›Ø·ùö&›€E!Ô¹?.W‹!× Ü Vè™m/FRЀåêÁ¯ñ¤Ðs3?Ã2š"YZJMôÆÝYçÈtü“r1EsÂbÎÏw«ÁÏÁ_øe¼?endstream +endobj +224 0 obj +845 +endobj +225 0 obj<>>>>>endobj +226 0 obj<>stream +xÚmP½R„0îyŠ+- ǶÞh§sz¨õ^XŽ8`6̍oï,,œ¤Úý~÷+QÉS°-ã×crß$·w vi M'»²ªÒšöz—ðJ!ÓMó)¨”Z1›¼”¥`>z²ˆƒ±gè‘áD2Ðnœ +ÔÏZs7Ã7 Xº@k8xsšƒq̈gà=a$tލz={O6Àþý(zíAŒÕ6Í£ñ[œ¸wá*…g“wí¬I¿Fîq„j ìºpAO¢aIj]€ ™Å4úá$“7’âXšqº¶¯Û«¢’SÕKŠýÛá{g;sž=.öOh¥Ò£´‘»Y)›*Ï"IeqXäuº…ìŸC?4ÉKòc„endstream +endobj +227 0 obj +287 +endobj +228 0 obj<>>>>>endobj +229 0 obj<>stream +xڝTÛn£0}ç+æqû-)Íå1‹’4RÕe•öÕ5êÆÖv6Êßï8´RoXÚs8sŽç˜ßIWtä0›Àõ¸J¾7ÉåzùšU¦³šöÛ6Ò8Çìé¢y7Ù|€¤7óle94h•0SÈó€ Þt2 åP*¾(-Õ,m}rU„sU——Õ8骪Ü!þÜ­‹0¯›ïZH„Æ2ív،7ÜÈÛm•nîÆùnñ(Ñû´b|„n,ëŸwp÷²)‡Oç¯ÔaÐŜ&üé/QÌ + +ÃU(äyx±j’ŸÉ_Ç68Pendstream +endobj +230 0 obj +425 +endobj +231 0 obj<>>>>>endobj +232 0 obj<>stream +xڝ“MSƒ0†ïüŠ=ê,•R<öÆv`‡ø"M16$ÒúñëMPÛéXrÚwöÙÝw—/„ùB¸Ží«oн«,†0¼±¡8‰‚ðúâùh–_â'£GGÝÆAÔéô•S­}Dª-Qk@Š M̤ÐJrȉ¨w¤¦_„Ÿ +þ ”Xþ£ÄR>œƒ_¤8ë‡/,JP ©¨™ Ô°kÀ¤ÝB&Uåä"t¶kÖ2‘’ZV’»ˆåê7"ÑL +¡ÔD¬-¬TMûè;Gó~vn&?Ø:'´q¢ŠE‘ö³Š׬¡kFà`BA‡ô­z4ÛrYê¼4dÖü—³B®‰‘luY)ö¬sÓ¶ ¸},‹i?µ¤joHm[Ûì”Ëjë`á ;N+¶gfÕã°"¢Ýöé%ßyã‘ù[GÉMÛÌÙ=*­SVïTwfÂtÔPaæå¤Ð£±ÉòÇÁM +‡6…I0‚.0 †0©”ïMk¥{wÞ'K­&sendstream +endobj +233 0 obj +381 +endobj +234 0 obj<>>>>>endobj +235 0 obj<>stream +xڝV[sÚ:~çWì0}H[<•2‡™6Ós Iò"luj[®$Cø÷]I†˜[Ò)0ƒlíõÛÝOúUó _úð{¦µ›y­u7oó%îôúÌ£«‹ˆg+øý*¸d)Ë´ú8ÿeð<'Ûìôˆ•žÇL1†¬h@.ŚG "¦)OX<[ +™RÍEøS¢!ƒ%îÛÐÆÍ"ˆDX#N6™Æbb@ϞO:¯žWúHxƨ˜& ,Ð|kѼ@Q͐zLGœ»c84©ômB7æ)_icªÀ$Öª(´aêèÔb¥‹¡þu:žÜÏ&D¿è:lbn¦3E9VX0fؒ†#ïsébW»™€éòõÑ4{ʕ.œÒˆ¦t…Fò„Qåš ÷ÔÜ%´ôðÝJšÏHëlhOøºîéëž×:ïô¼lxAFùGjxäl·’¯‘;f× ç&8¯øH’íFˆ¨ߨÜ&¦jvÏï5}Ef£?ÊðQ`^Cx¾òÛÞóGðû~sÐkûû†÷ó"WMCD_̊¹:/ðôô4„Xë|Øjm6rAþX}\ÎøûEÚ«÷|…Ñ7Ã#—å;gä;oÈûgäýcùÖá™Õ4üY=µBk‘þÑÁ¥¥¹y½yráŒî¶ö¬tjüÅàŽ¢\ò›êõ\,'x}Á­ŸÖ/ÞÃ-êò¾®œÕÝòBuéFô¼¨µŒg›m2¯ý[û DÝAYendstream +endobj +236 0 obj +1069 +endobj +237 0 obj<>>>>>endobj +238 0 obj<>stream +xÚÕVQ“Ú6~çWì0™ÉqÆÂ9Hó’ËÝÌ=$½Nè3!¯±ZYr%ù€vúß»² Î¥×´O†ÑZÚOß÷iWð[ALoÉ,|DÑ{¿ìï¦À,3š™]O£kX¦ÎTV dRá[øÁ[N¡預ÎI½éCTŠÖŠVä܃0)Bά5(ãÇW㠃I¼¸š.â)QþávW«~Ô74æÀ®‚ú FH2¦aþ=ñ¹«´ðÒhw\™4Œ ez]µë"ŸxAÆ4ËN¾Ž&³ì[ésà°QfÍ8aJ—s¥È7¼”ž+ù;¦°ºè0Ë\ºþê÷Íè³)Ðç´Û­rHÐ‹h5€%™k´ÚD¶~âN`¶oèèØl¥žlÎäæç‡Ï µG›q:}%זÛ=d'Ò¹9|O©"J‹™ÜÁÖØ”Ò;+³E+¸Ã DT¥;©9Dµ¢†~›üM¿”_ە¢PܒW}繗¢œÊƒ&N{×é•NÑR®ÅP~ +4vÊD45_|˲6¦ÓÐ\ÿ‚Om¦0’I4;Æ>Q¨?£¿Y·œü=ø}øÄjaŠ€9rÒBʝ°rzqš¯î¬CzjÐ ëGÇ•º¬<l!ý×¢©Ï¹Þ¯ÃÚ¾³fóð[F“õ/љÜT¶AüÈ5ß`­ÿAñÚÛ¾¡¬Ñ›I’Ø4>>>>>endobj +241 0 obj<>stream +xڕUMsÛ6½ëWìèËQ¢>,Ûi‰wrhêNԞ4ãÁ¥„”­dúß»DY¤•J3¢,ÞîÛ}»üÜKaLߘ^/{o—½Ñí®’ , ¿wq¹€e~6:,ÿîa˜¦~ çð‚Kfíõu®ïÝFØÕÙjð†p£Ëªv;x qÿq5H:—»XµC{ J+욎ZëÖ¢š9xþÃïɵEc*ý€¶LÖøÆÉ~yMÑÑOJÿ;ø]NÑ1ð ôî Vg{´Ç=™uð¾¶Ù$I‡žAWEH»ÕàUëè_¿Ý^A:O.}-†TŒáô*™ùÓ·ôø‹Á2‰ö`9U#ŒÙe2ßÛ%)|d¥Pëh6Œ&ìÂm€ÁZêŒI°\Wvä„ ³J8&ÅÌ)àþ’ÔÜì¿Z3×^ ûÉ1‡G›èx²4r¬œÐ +œÚSË£Þüy÷ „rh +Æ¤È 3»&â퓍à(këèæZ¨H:Î+ƒ…x„>¯+Û÷´üŸ.µ¸×¢™À¯]¿‡` V’"Ì!ÛAQ+îyu|3³®KTÎG‹ +I­¤Uk52ùf‰¤æÏ+$½89#Í«ZåÔ\º–¡{@¤4h“[ÏÓç÷~{ Ô Ž™;:nø¾Q»½ëeÓæ£¤¤3°º6T§B2Gê3§oI ‚÷“žN’‹FÂx§yÈkòxRÉiì„?BŠÒ%‰G!0•?вÄ\Щ±ÐÒç3cÀuéÝCFìÿé$+GˍȨłDÿ×1Ìãaz¸Òju’3´Êñ*1ß¼6Æûõ‰¢6)b_t¦L8*Ø÷h¢E€ïŒš»ê£eþãÑò†òê+»ã§•êËÓ¿w}`U…d•Çـ@‹È&bwJÒÜû¦ÛÔÃ!?‡åÓ ú¦êæÿOueä·a[ìJ¦%­ ¢b÷×r,~Z+ÏßÃ~XEïô$Ü8" MƒÉ€óԞ|©Žn/÷\Ò4%Л> ïúp£U!Öµ Ôá7¦Ø;ÉB*†élA·†‹É8&lz*a³ÅŒŒ‚E:÷?zÿ…†•endstream +endobj +242 0 obj +855 +endobj +243 0 obj<>>>>>endobj +244 0 obj<>stream +xÚÍUMoÚ@½ó+žr"¨Ö|7§†¦·V©âÞ"¡e½€[Ûëz× Tõ¿gv×|*I.­@È3Ì{3oö­ü»ÁÐ¥Coh¿"kÜFÎ—.&AˆhasÃñQÜ4ÛBÆr$7U¡gf•Ðegææ:úI¨ Ø [X›píÞ$è[äm0ă)+aªRê}iÏwè¢Ýƒº0`øÆ³$_ú²>«‹Â¡gû”¦Ð;6ä<“zÅ);—HÕF–‚k‰MbV¨òX–Z(jKÿš”96ªŒ5xãjF¸ˆææý÷Ò ašr­/\ŸÑ뮏°Tï¾:»àXöæßE¯ðýèm¾÷Ó¾Ýó÷’åq0ù™ûÿåý¨ïµ»GÜîâÿÜèãú°cä÷aÈ÷’qÚ§*_$˪tÞÀWžó¥tÇ}Ÿrç•6ëÕ…] bC›ìûA]o±Ás»‹ßOë×vendstream +endobj +245 0 obj +575 +endobj +246 0 obj<>>>>>endobj +247 0 obj<>stream +xÚµUMoÚ@½ó+¦9 á£i„¤j¤6MWUU¢hmñ6¶×Ý]—Òªÿ½³þ @ J§};óæÍ<ó½fC‡~6 »Ð€×ΜZûõìckN@wƒáЀã×Ï(2‰Ò,Ѫá|+p=«[àZý‘u\â,®X̓yëƒm— îÀêÐ$ŠÀ+“AÂbT BFA!KS”S ®CÈ¥ò„DŸnõ1…¾‚YýÀysys7}uãL®œƒ#Sª¬|s=qÖ®µgÍm€O(q $èaúéúx¢QÌCˆ¸+™\Bœ)MÅç<)8±äåVÍTRʟ†›Éu·Eªè.^e¦J#g™3L²%Ӝ8¯i¤èjb‚?PB*”ân„ @,Š~è=x!z÷4 p—yƒžˆS¡´vL°×]Mšbç£ʉÎK?:È©ˆ ÜHx÷AN1Ÿ3Ñ’˜ä„yájâ/‹tµiõVúUrÚæ`šßüÞ8™ 'Y–µõnSüƒÙçYÃ)tN€Ã+:(RE³zžœL݆*²qóµs;kÌæÕááÊcÕ>~K‰É‹ÎÅÝåùۋ“ÇyüÛëgÆun·¢U/dÉÕ³šóÅÞÿ_½ð*$Iðb]ƒhW"»ß£N™‘¨žî%¹NnG!!¦³ºMÌ7íH_<úv=¿BiãQé9Û¶É̓ãQþ3_|úCø<+ ïXÂæ¹ à:b¹a[vHoZÃngçaاP~gMà©}¨ýû‡Žendstream +endobj +248 0 obj +749 +endobj +249 0 obj<>>>>>endobj +250 0 obj<>stream +xڕV]OÛ0}ﯸÊ0š6´ +Û$`LBb[»í&ä&7­‡kw¶Ó&þû®í”,ác¬­’ؾ¾_çø¤¿: ôé›À`×ýÒEçxÒé}A2ˆw`’ÓÚî~ⳍãxDc{+psò3X%Á¦;Å»61ƒ3™¡´Ìr%ƒí°¶Ýٍ‡ÎöHHU†0*½1€2Ê`Ó[˜j–Þ 5`æŒÌ¦8ãJnç`çj‰’Ë™·¢‘K\b 2ðnÉRB®„P¥qIPèPU¶a,ÓÖyhì–[Ô>BðÌdÜ÷ÅPb;`–4oª ”mÙù€KA£¬é¸=ää¶Úu®Ì†Â4§B™¨Búþ„öa!˜<­'nð»1òaBo ΕZºp+¦a«×0kîémµ|lÁ…VT±¡Fª)m_1Q ´Z–VÁh4Šã¸½í¥ äJÃÕ‡wÐ?o!é÷ýӛ7W›-ÛvQ™º¶snÈÁÕæáÓ«Ì>¹zßß7‰Ùu}]SsLÝØõ¤ ®X\jà¢LEÛ¡0èîT‘»ñœ®Ž4Q9ç£ö>¦0% +·¸q΂Ê/¸£Qdˆùé< +å §Ã§žÀÈÒ9D)£ÜB6æ¬67÷j>…¨„ӚÝ^ò-pÚÐ8ç0žMN¯Ï>œŸÂÁ#pþÞËð¹ÏT#»i/Tå=P* +)gÿãó¾)p n‰›Â˜ZNnŸ—·JW N€F£A½"ÜJ¥3êoàMřm@›ÆW›Þ?®jˆÓN‡øm‰èȑ2]Ëì_<’lôËÉ +Ó³"0˜ø´dšçh¸‰éx³È¾ -´„oþÔ?[êEí²Ê×Z«‚ÂWz¡½JÜ G5^B£°½š›ÁžzWó­÷EÔ2/…ÏòWt„R%WôŽ¡ª@¸T–*DFóMeª”%#ìHÿîP+w狥V+ºÎ4[À5©Â‚Éôõ'®FÃïPåÕÑ#2ôš3—}:ŒÐ…Ä©æûJG»ÝGê¹>¹ä±nTÕ¦ýªü$Iâýú-òõb 'Jæ|Vhÿ‚OL²™—@¸Ì3­› ÷hWwo§ï6%ûnr8Ð\ÿ‰ÿ +§“Îçι¸j2endstream +endobj +251 0 obj +856 +endobj +252 0 obj<>>>>>endobj +253 0 obj<>stream +xÚí“MOƒ@†ïüŠ9êa‘ᣀ µåf¬Ïd¥‹b +‹Ó­¦ÿÞ]¨6Æ»lB6»ï3oÞxµ½B¼”u[i C^†±0 }È×g7ÉJ½s“Ü=n¬D'IA*©9Ï_4¢YØ.0ÏwížÍvMÃi²‚%I6—àtŒ“c´Å/Ÿ‘cG õ[9¸@&ÞÕj?²ëÅ7LVé̽£yoà‹ÂMæ²Ü5¢U\Õ²e "IS™—<´\[1%ْêV1ÎÒZ÷f¢ô'J½áÃVœ¨L++vµÙŒ;Ì]ÊNŒB÷ʯз¼|®[&é]'H§lŸX¶ß*›\S+ ";>zͅâ:éæb[Rݙ6}3áþӄ§=ùçŽ_~ô9=]c†C‘ŸS?ôíh˜Ææ`‘[÷Ö.Ë3ýendstream +endobj +254 0 obj +333 +endobj +255 0 obj<>>>>>endobj +256 0 obj<>stream +xÚ-ŒA D÷œb–ºhªÒµÝ™Tû=*45”Ðx}%53«É{ófüjŸ{wì@lÓÖd!¶ª¬¡$=V͵ëÑoÇaŽ:Á㤽Œ3>¡›´_ӓ‹Sü%ÉóXIUî°¼ 6}t4 æÛdp1¯Ú]†ÄÎì ý‚*;endstream +endobj +257 0 obj +135 +endobj +258 0 obj<>>>/Annots 106 0 R>>endobj +259 0 obj<>stream +xÚݛKsÛ8 €ïù:îVŸmºé졏m¼½»ŽÒz'¶ZÙn'ÿ~I”ÄLøy9°>šóýJ•ÿE- e‹ÍîêÕêêō+„+V÷…°ª”…­_Ýý¶Z~h‹î¾¸îöÇv<ü¾ú÷êÏÕUUVžÞDxûø&4 +«ÿØ®ïðù¡¸ ü'_ï¿/nL!Dè1<æ 7QÌâGä®P¦lr>H‘r»é¾µ4R*ìUߝÿJ¹ø—˜Õ„²AÓÒø÷]adi°A¨Z£ª½½­´QÓ%¡ë tçŸAÛÓ.PAÝùY±½ßnÖÇm·ÿµÖM]ÖKÒ;§Û8â¤ÛؘÕmШþQ§’Ó)’›º´9ÅHº}<Ûá ãóÞ@J ?:¹ȑöþGÛÿض?m-J·ã0V1®ñƒB«@ƒ²Šq®Ä™®«$²¨‚Wdh”#êu·9íütŸçM¨u©s`úÓH?£žÙ4‚ ø¦–CÀ‡Ïg|S+Ւø o‚º2>H‘ò±½oûv¿i3ztˊ?¿x)fò{ áç…{cã¸%îSMY Îõ?n “ÏúÉoª`´) ä@J¾D¤ kŸ×hœM´Ó4Ȁ¤-„cɦ‰Dn*»22Š‘ôþøµí sŒ‡,Q…X4…¡aÉ ó>$áCŠHÂùab@ŠŸÏ H2hÇN1 ñ²ñ%ãGi¢Ülý¢y4yxW¸h–) Ä õv½_iƒafÖV®\äšÖ0ÎSYˆìqBÇÆ™­ª!è+>¤a®*žöb$½ÞöíæØõó¼ "¸RXÏf@”#ðö؟6ÇS?³ Qauöü&c,¤S4¨ð¦øÜ· ‘(ã¢8rn»S¿!|hòtX¸Åg,”Þ8Մ[–ïp6©Ý˜r AÚÄGø¬Â­Yˆzè'3KB]wûûí—Só6±žp<µ áŒê¿0BÙ gŸ)È2Ùh£†dŸÏJ6ÚhˆíšN6 ¯¿CËø EʪïNŸ©|3yÞÿVíƒOC1Ò>¶ßºžØáLž‘PûH˜ÿ4#íCßùUùa»ÿ2³ªXF(,kÆït5f+hœ—­´4›­RB¨¡ÇÌêúaí5JŸ¸ØjQ«N½²ž¤šØ Úl@¥lªA.ae`”7—z„ÅiÔO¢1QÄ©Q¡KÔ)›(ìÜS2ŠuÊ}XUÍ*4n;¶nå”ZUã 4H¥VyB,d”ŠdQ™O§h”#ê]ÇNT¹}ÚðjȪj=œ Áç³r¨J +CçЄ7ê)¤H¹íî?×=‘D'?ù¥O™ Å&H=´ëÃÜ¢Ó¯ÿ›nÙ=û•c†Æy9PY0›S~K,òP9ŸÚþ@.='‡#ؐG3Ê#ìÝi÷¹í©åÉ¢>g]±TXR~½×€A¸ü™ÈáÐZçh”#êM»oûõe{N«JÁ¤V•mØ šÈ~‹ú„Œb$­ÚÃqvf*µÈmN©RÄ} 46H¥J ÛÃfÐDn¬÷،Œb™¶712_REEæOé°L[ùCã¬*]œd/©ZÖ@ÜÁ²"ã8RÞÊkÂÚg~hœ—ýdƒUؗdþ±~«¡Ã4‡AŒ¤UÛïf–r™K ^½‹»q –+îJ‹õӗdaÁ?ÂYS†FyBmúnÿ8§XvF‹R¬ +³RCéT„Õ4΋ ‹ª¯ÈÈ †üªàI(FÎuwç³q:UO`áðã åC©÷ûiÛ·D¡Êšr9‡º‚©!J‰uÝ0½ qfXQqˆ¯˜ ¢†═¬‡=nŸSÊ ?}záYäq{¹¤wÂ:µ CP;8 1kÚ§G¥ToÊ.¡V9å{·Þ«À%ìOX5V2†`Wlj¬Dä FÉ©ÙÂZ¿ÀËà(WùÝò¾Ási“ ¢bqtYhPéQ8,¿bÒ£È.ìt32ˆé洏‡y‡åÞTzªSMÏJQcu8LhP³RÔXÜõ:e;±Á¹38ÊvÎÍ©ÑB ÆeÉ2qP£M“uíD×ÎÐ(×ËwlÍ8¶vi[¡°A:¶©R†Qœc#مMCFq"½m_»»¹“J»À‹sìŒô¿zH7Ð gd¼Ž:åÙèØS8Êö?pl 5^—$«ÛAR§œ£x×F6ºöŽr„]¶s ¬G‡dÕ88·)Ãhι‘콈ŒŒb$}Z÷Ûð‡Ùƒ½4÷†ž–®Ӎ«™lã0XjÖ± ~=å‚ôRVâŒò5îgÅlg]êãÁàÏS2Hu~Åt™ÞÌܽª«tB¥à3å˵H9Å0®ŒØ&xì BĬ¿Íù°4 ½ÛÎÍESé%~¦æ¢iRr1¬+#\yJ)’.ߙµ÷/Z3ÛmRn1¬3#œyJ)’.ڙ•Ý”`î)Ԝe\¡.ܧ›BA˜ß ¾ }´ ?õÅMƒ‡&üC•mšáßAò¡ãUÎâÃÃ:N ·Ô2l‹Jüûê?®²¸ãendstream +endobj +260 0 obj +1984 +endobj +261 0 obj<>>>/Annots 134 0 R>>endobj +262 0 obj<>stream +xÚ՘Ár›0†ï<…ŽíÁ +HB׸uOí¤1}š`;Æ´O§oߕ´ +à©=ÙN2Ìì,|kýÚ_kò+a$…_F2iþžšä¾LîVš0MÊ a2£œH%àZ>¿+«ïûš´²l}}èïËÉÇ2Ii +saæòø‰(NS"³žkˆ.¨Ä`OÖ¦ÂÙݖܭr˜©© `¦]Á{*)#³UFà†°,©‰e0°/U³;l l ¥X>˨à.zÁ&#‚rW/¨ f52réEä1‘̤¤ùy‹úÐ>Øøªßµ‡·•À…” ¨—I£c´€5Šœf̪^ŒÃV?5¯Þ֐B“1¤å¾:ëãL 2Ø¥‹·à÷¤°ý=é‚PO +­)v¥ŠZÛ³µ'pÌ#ìö­- +Æó2Ú (ca|Š2ÆÌíÙÎÜ8ævÓö #÷övAÈÞBe~Æ{{²V°ö ÓH‚©xì+‹¯¥ËùÕœ©HW += »R¦¨hÜÚHFkÑ.ïP7`옄¹°³Á­ÊA sé§N76²ÑØc8ævÝÆVcgÜNg6 }Fnjd¥ŒXc2¦‘´lŸë·UãŠ\ßÐþ—¾dz4plìKžú£ãæF6öåîòv«}éLåðz゠‚©òGǝlÆÍ·Â ó[÷ö3½ ²_Ko²bv¹\iwŽ¥°×.¼( +|Q„犿XÏË9bÂ"@»I—öœu»éW]87ì¼Ù– Î¥=®ìړycžßë`F!ÑÂïµÍ{Ücý³íúÀRGÀ‰âüÓÁ mÕvÍÌ¡&.Ö6L›t·*pÆ*Ü¿Á/¿=¬Íÿ6»í©³gù\ªmmÎò°¯ì²`¹‚%.·«ØíP°¯É_*Ïk%endstream +endobj +263 0 obj +710 +endobj +264 0 obj<>endobj +265 0 obj<>endobj +266 0 obj<>endobj +267 0 obj<>endobj +268 0 obj<>endobj +269 0 obj<>endobj +270 0 obj<>endobj +271 0 obj<>endobj +272 0 obj<>endobj +273 0 obj<>endobj +274 0 obj<>endobj +275 0 obj<>endobj +276 0 obj<>endobj +277 0 obj<>endobj +278 0 obj<>endobj +279 0 obj<>endobj +280 0 obj<>endobj +281 0 obj<>endobj +282 0 obj<>endobj +283 0 obj<>endobj +284 0 obj<>endobj +285 0 obj<>endobj +286 0 obj<>endobj +287 0 obj<>endobj +288 0 obj<>endobj +289 0 obj<>endobj +290 0 obj<>endobj +291 0 obj<>endobj +292 0 obj<>endobj +293 0 obj<>endobj +294 0 obj<>endobj +295 0 obj<>endobj +296 0 obj<>endobj +297 0 obj<>endobj +298 0 obj<>endobj +299 0 obj<>endobj +300 0 obj<>endobj +301 0 obj<>endobj +302 0 obj<>endobj +303 0 obj<>endobj +304 0 obj<>endobj +305 0 obj<>endobj +306 0 obj<>endobj +307 0 obj<>endobj +308 0 obj<>endobj +309 0 obj<>endobj +310 0 obj<>endobj +311 0 obj<>endobj +312 0 obj<>endobj +313 0 obj<>endobj +314 0 obj<>endobj +315 0 obj<>endobj +316 0 obj<>endobj +317 0 obj<>endobj +318 0 obj<>endobj +319 0 obj<>/Outlines 264 0 R/PageMode/UseOutlines/OpenAction[198 0 R/XYZ null null null]>>endobj +xref +0 320 +0000000000 65535 f +0000000015 00000 n +0000000218 00000 n +0000000279 00000 n +0000000353 00000 n +0000000431 00000 n +0000000508 00000 n +0000000587 00000 n +0000000663 00000 n +0000000744 00000 n +0000000802 00000 n +0000000905 00000 n +0000001009 00000 n +0000001114 00000 n +0000001219 00000 n +0000001324 00000 n +0000001429 00000 n +0000001534 00000 n +0000001639 00000 n +0000001744 00000 n +0000001849 00000 n +0000001952 00000 n +0000002056 00000 n +0000002161 00000 n +0000002266 00000 n +0000002371 00000 n +0000002476 00000 n +0000002581 00000 n +0000002686 00000 n +0000002789 00000 n +0000002893 00000 n +0000002998 00000 n +0000003103 00000 n +0000003208 00000 n +0000003313 00000 n +0000003418 00000 n +0000003523 00000 n +0000003628 00000 n +0000003733 00000 n +0000003838 00000 n +0000003943 00000 n +0000004046 00000 n +0000004150 00000 n +0000004255 00000 n +0000004360 00000 n +0000004465 00000 n +0000004570 00000 n +0000004675 00000 n +0000004780 00000 n +0000004885 00000 n +0000004990 00000 n +0000005095 00000 n +0000005200 00000 n +0000005303 00000 n +0000005407 00000 n +0000005512 00000 n +0000005617 00000 n +0000005722 00000 n +0000005827 00000 n +0000005932 00000 n +0000006037 00000 n +0000006142 00000 n +0000006247 00000 n +0000006352 00000 n +0000006457 00000 n +0000006560 00000 n +0000006664 00000 n +0000006769 00000 n +0000006874 00000 n +0000006979 00000 n +0000007084 00000 n +0000007187 00000 n +0000007291 00000 n +0000007396 00000 n +0000007501 00000 n +0000007606 00000 n +0000007711 00000 n +0000007816 00000 n +0000007921 00000 n +0000008026 00000 n +0000008131 00000 n +0000008236 00000 n +0000008341 00000 n +0000008446 00000 n +0000008551 00000 n +0000008656 00000 n +0000008761 00000 n +0000008866 00000 n +0000008971 00000 n +0000009076 00000 n +0000009181 00000 n +0000009286 00000 n +0000009391 00000 n +0000009496 00000 n +0000009601 00000 n +0000009706 00000 n +0000009811 00000 n +0000009916 00000 n +0000010021 00000 n +0000010126 00000 n +0000010231 00000 n +0000010336 00000 n +0000010441 00000 n +0000010545 00000 n +0000010649 00000 n +0000010753 00000 n +0000010857 00000 n +0000011553 00000 n +0000011659 00000 n +0000011765 00000 n +0000011871 00000 n +0000011977 00000 n +0000012081 00000 n +0000012186 00000 n +0000012292 00000 n +0000012398 00000 n +0000012504 00000 n +0000012610 00000 n +0000012714 00000 n +0000012819 00000 n +0000012925 00000 n +0000013031 00000 n +0000013137 00000 n +0000013243 00000 n +0000013347 00000 n +0000013452 00000 n +0000013558 00000 n +0000013664 00000 n +0000013770 00000 n +0000013876 00000 n +0000013980 00000 n +0000014084 00000 n +0000014189 00000 n +0000014295 00000 n +0000014401 00000 n +0000014635 00000 n +0000014669 00000 n +0000014703 00000 n +0000015402 00000 n +0000015451 00000 n +0000015500 00000 n +0000015549 00000 n +0000015598 00000 n +0000015647 00000 n +0000015696 00000 n +0000015745 00000 n +0000015794 00000 n +0000015843 00000 n +0000015892 00000 n +0000015941 00000 n +0000015990 00000 n +0000016039 00000 n +0000016088 00000 n +0000016137 00000 n +0000016186 00000 n +0000016235 00000 n +0000016284 00000 n +0000016333 00000 n +0000016382 00000 n +0000016431 00000 n +0000016480 00000 n +0000016529 00000 n +0000016578 00000 n +0000016627 00000 n +0000016676 00000 n +0000016725 00000 n +0000016774 00000 n +0000016823 00000 n +0000016872 00000 n +0000016921 00000 n +0000016970 00000 n +0000017019 00000 n +0000017068 00000 n +0000017117 00000 n +0000017166 00000 n +0000017215 00000 n +0000017264 00000 n +0000017313 00000 n +0000017362 00000 n +0000017411 00000 n +0000017460 00000 n +0000017509 00000 n +0000017558 00000 n +0000017607 00000 n +0000017656 00000 n +0000017705 00000 n +0000017754 00000 n +0000017803 00000 n +0000017852 00000 n +0000017901 00000 n +0000017950 00000 n +0000017999 00000 n +0000018260 00000 n +0000018412 00000 n +0000024803 00000 n +0000024825 00000 n +0000024938 00000 n +0000025040 00000 n +0000025060 00000 n +0000025200 00000 n +0000026140 00000 n +0000026161 00000 n +0000026274 00000 n +0000026462 00000 n +0000026483 00000 n +0000026623 00000 n +0000027216 00000 n +0000027237 00000 n +0000027350 00000 n +0000027543 00000 n +0000027564 00000 n +0000027695 00000 n +0000028308 00000 n +0000028329 00000 n +0000028442 00000 n +0000028631 00000 n +0000028652 00000 n +0000028783 00000 n +0000029727 00000 n +0000029748 00000 n +0000029879 00000 n +0000030166 00000 n +0000030187 00000 n +0000030327 00000 n +0000031243 00000 n +0000031264 00000 n +0000031395 00000 n +0000031753 00000 n +0000031774 00000 n +0000031914 00000 n +0000032410 00000 n +0000032431 00000 n +0000032562 00000 n +0000033014 00000 n +0000033035 00000 n +0000033175 00000 n +0000034315 00000 n +0000034337 00000 n +0000034477 00000 n +0000035383 00000 n +0000035404 00000 n +0000035544 00000 n +0000036470 00000 n +0000036491 00000 n +0000036631 00000 n +0000037277 00000 n +0000037298 00000 n +0000037438 00000 n +0000038258 00000 n +0000038279 00000 n +0000038419 00000 n +0000039346 00000 n +0000039367 00000 n +0000039507 00000 n +0000039911 00000 n +0000039932 00000 n +0000040045 00000 n +0000040251 00000 n +0000040272 00000 n +0000040427 00000 n +0000042482 00000 n +0000042504 00000 n +0000042659 00000 n +0000043440 00000 n +0000043461 00000 n +0000043516 00000 n +0000043621 00000 n +0000043765 00000 n +0000043871 00000 n +0000043991 00000 n +0000044100 00000 n +0000044249 00000 n +0000044359 00000 n +0000044466 00000 n +0000044620 00000 n +0000044731 00000 n +0000044848 00000 n +0000044964 00000 n +0000045128 00000 n +0000045234 00000 n +0000045353 00000 n +0000045468 00000 n +0000045572 00000 n +0000045728 00000 n +0000045837 00000 n +0000045952 00000 n +0000046064 00000 n +0000046163 00000 n +0000046310 00000 n +0000046407 00000 n +0000046507 00000 n +0000046665 00000 n +0000046805 00000 n +0000046905 00000 n +0000047012 00000 n +0000047162 00000 n +0000047262 00000 n +0000047369 00000 n +0000047517 00000 n +0000047617 00000 n +0000047724 00000 n +0000047874 00000 n +0000047974 00000 n +0000048081 00000 n +0000048227 00000 n +0000048327 00000 n +0000048434 00000 n +0000048585 00000 n +0000048685 00000 n +0000048792 00000 n +0000048940 00000 n +0000049040 00000 n +0000049147 00000 n +0000049297 00000 n +0000049397 00000 n +0000049504 00000 n +0000049636 00000 n +0000049743 00000 n +0000049842 00000 n +0000049960 00000 n +trailer +<> +startxref +50146 +%%EOF diff --git a/doc/cmp.shtml b/doc/cmp.shtml new file mode 100644 index 0000000000..cc6315d3f1 --- /dev/null +++ b/doc/cmp.shtml @@ -0,0 +1,717 @@ + + + + + + CUPS Configuration Management Plan + + + +

Scope

+ +

Identification

+ +This configuration management plan document provides the guidelines for +development and maintainance of the Common UNIX Printing System ("CUPS") +Version 1.0 software. + +

System Overview

+ +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +This configuration management document is organized into the following +sections: + +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - File Management
  • +
  • 4 - Trouble Report Processing
  • +
  • 5 - Software Releases
  • +
  • A - Glossary
  • +
  • B - Coding Requirements
  • +
+ +

References

+ +

CUPS Documentation

+ +The following CUPS documentation is referenced by this document: + +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan +
  • CUPS-IDD-1.0: CUPS System Interface Design Description +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual +
  • CUPS-SDD-1.0: CUPS Software Design Description +
  • CUPS-SPM-1.0: CUPS Software Programming Manual +
  • CUPS-SSR-1.0: CUPS Software Security Report +
  • CUPS-STP-1.0: CUPS Software Test Plan +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual +
  • CUPS-SVD-1.0.x: CUPS Software Version Description +
+ +

Other Documents

+ +The following non-CUPS documents are referenced by this document: + +
    +
  • IEEE 1387.4, System Administration: Printing (draft) +
  • IPP/1.0: Additional Optional Operations - Set 1 +
  • IPP/1.0: Encoding and Transport +
  • IPP/1.0: Implementers Guide +
  • IPP/1.0: Model and Semantics +
  • RFC 1179, Line Printer Daemon Protocol +
+ +

File Management

+ +

Directory Structure

+ +Each source file shall be placed a sub-directory corresponding to the software +sub-system it belongs to ("scheduler", "libcups", etc.) To remain compatible +with older UNIX filesystems, directory names shall not exceed 16 characters +in length. + +

Source Files

+ +Source files shall be documented and formatted as described in Appendix +B, Coding Requirements. + +

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. + +

Documentation on the CVS software is included with the whitepaper, "CVS +II: Parallelizing Software Development". + +

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: + +
    +
  1. STR is closed with complete resolution
  2. +
  3. STR is closed without resolution
  4. +
  5. STR is active
  6. +
  7. STR is pending (new STR or additional information available)
  8. +
+ +Trouble reports shall be processed using the following steps. + +

Classification

+ +When a trouble report is received it must be classified at one of the following +levels: + +
    +
  1. Request for enhancement
  2. +
  3. Documentation error
  4. +
  5. Unable to print a file
  6. +
  7. Unable to print to a printer
  8. +
  9. Unable to print at all
  10. +
+ +The scope of the problem should also be determined as: + +
    +
  1. Specific to a machine
  2. +
  3. Specific to an operating system
  4. +
  5. Applies to all machines and operating systems
  6. +
+ +

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. + +

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). + +

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. + +

Notification

+ +The user or vendor is notified when the fix is available or if the problem +was caused by user error. + +

Software Releases

+ +

Version Numbering

+ +CUPS uses a three-part version number separated by periods to represent +the major, minor, and patch release numbers: + +
    +
    +major.minor.patch
    +1.0.0
    +
    +
+ +Beta-test releases are indentified by appending the letter B followed by +the build number: + +
    +
    +major.minor.patchbbuild
    +1.0.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: + +
    +
    +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: + +
    +
    +1.0.0b1    First beta release
    +1.0.0b2    Second beta release
    +1.0.0      First production release
    +1.0.1b1    First beta of 1.0.1
    +1.0.1      Production release of 1.0.1
    +1.1.0b1    First beta of 1.1.0
    +1.1.0      Production release of 1.1.0
    +2.0.0b1    First beta of 2.0.0
    +2.0.0      Production release of 2.0.0
    +
    +
+ +

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. + +

Testing

+ +Software testing shall be conducted according to the CUPS Software Test +Plan, CUPS-STP-1.0. Failed tests cause STRs to be generated to correct +the problems found. + +

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. + +

Glossary

+ +

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. + +
+ +

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 Printer 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 + +
PCL +
Page Control Language + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
+ +

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. + +

Source Files

+ +

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 +".cpp" for C++ source files. All other "include" files shall have an +extension of ".h". + +

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: cmp.shtml 351 1999-05-21 20:54:09Z mike $" tag: + +
    +
    +/*
    + * "$Id: cmp.shtml 351 1999-05-21 20:54:09Z mike $"
    + *
    + *   Description of file contents.
    + *
    + *   Copyright 1997-1999 by Easy Software Products, all rights
    + *   reserved.
    + *
    + *   These coded instructions, statements, and computer programs are
    + *   the property of Easy Software Products and are protected by
    + *   Federal copyright law.  Distribution and use rights are outlined
    + *   in the file "LICENSE.txt" which should have been included with
    + *   this file.  If this file is missing or damaged please contact
    + *   Easy Software Products at:
    + *
    + *       Attn: CUPS Licensing Information
    + *       Easy Software Products
    + *       44145 Airport View Drive, Suite 204
    + *       Hollywood, Maryland 20636-3111 USA
    + *
    + *       Voice: (301) 373-9603
    + *       EMail: cups-info@cups.org
    + *         WWW: http://www.cups.org
    + *
    + * Contents:
    + *
    + *   function1() - Description 1.
    + *   function2() - Description 2.
    + *   function3() - Description 3.
    + */
    +
    +
+ +The bottom of each source file shall contain a trailer giving the name +of the file using the CVS "$Id: cmp.shtml 351 1999-05-21 20:54:09Z mike $" 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: + +
    +
    +/*
    + * End of "$Id: cmp.shtml 351 1999-05-21 20:54:09Z mike $".
    + */
    +
    +
+ +

Functions

+ +

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.) + +

Functions with a local scope shall be declared "static" and be lowercase +with underscores between words ("do_this", "do_that", "do_something_else", +etc.) + +

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: + +
    +
    +/*
    + * 'do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +static float     /* O - Inverse power value, 0.0 <= y <= 1.0 */
    +do_this(float x) /* I - Power value (0.0 <= x <= 1.0) */
    +{
    + ...
    + return (y);
    +}
    +
    +
+ +

Methods

+ +

Naming

+ +Methods shall be in lowercase with underscores between words ("do_this", +"do_that", "do_something_else", etc.) + +

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: + +
    +
    +/*
    + * 'class::do_this()' - Compute y = this(x).
    + *
    + * Notes: none.
    + */
    +
    +float                   /* O - Inverse power value, 0.0 <= y <= 1.0 */
    +class::do_this(float x) /* I - Power value (0.0 <= x <= 1.0) */
    +{
    + ...
    + return (y);
    +}
    +
    +
+ +

Variables

+ +

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. + +

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". + +

Documentation

+ +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 */
    +int that_variable;   /* The current state of that */
    +
+ +

Types

+ +

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.) + +

Documentation

+ +Each type shall have a comment block immediately before the typedef: + +
    +
    +/*
    + * This type is for CUPS foobar options.
    + */
    +typedef int cups_this_type_t;
    +
    +
+ +

Structures

+ +

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.) + +

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: + +
    +
    +/*
    + * This structure is for CUPS foobar options.
    + */
    +struct cups_this_struct_str
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+ +

Classes

+ +

Naming

+ +All class names shall be lowercase with underscores between words +("this_class", "that_class", etc.) + +

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: + +
    +
    +/*
    + * This class is for CUPS foobar options.
    + */
    +class cups_this_class
    +{
    +  int this_member;   /* Current state for this */
    +  int that_member;   /* Current state for that */
    +};
    +
    +
+ +

Constants

+ +

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.) + +

Typed enumerations shall be used whenever possible to allow for type +checking by the compiler. + +

Documentation

+ +Comment blocks shall immediately follow each constant: + +
    +
    +enum
    +{
    +  CUPS_THIS_TRAY,   /* This tray */
    +  CUPS_THAT_TRAY    /* That tray */
    +};
    +
    +
+ +

Code

+ +

Documentation

+ +All source code shall utilize block comments within functions to describe +the operations being performed by a group of statements: + +
    +
    +/*
    + * Clear the state array before we begin...
    + */
    +
    +for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +  array[i] = STATE_IDLE;
    +
    +/*
    + * Wait for state changes...
    + */
    +
    +do
    +{
    +  for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
    +    if (array[i] != STATE_IDLE)
    +      break;
    +
    +  if (i == (sizeof(array) / sizeof(array[0])))
    +    sleep(1);
    +} while (i == (sizeof(array) / sizeof(array[0])));
    +
    +
+ +

Style

+ +

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: + +
    +
    +{
    +  int i; /* Looping var */
    +
    + /*
    +  * Process foobar values from 0 to 999...
    +  */
    +
    +  for (i = 0; i < 1000; i ++)
    +  {
    +    do_this(i);
    +    do_that(i);
    +  }
    +}
    +
    +
+ +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])
    +{
    +  case STATE_IDLE :
    +      do_this(i);
    +      do_that(i);
    +      break;
    +  default :
    +      do_nothing(i);
    +      break;
    +}
    +
    +
+ +

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. + +

Return Values

+ +Parenthesis shall surround values returned from a function using "return": + +
    +
    +return (STATE_IDLE);
    +
    +
+ +

Loops

+ +Whenever convenient loops should count downward to zero to improve program +performance: + +
    +
    +for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
    +  array[i] = STATE_IDLE;
    +
    +
+ +

Software Trouble Report Form

+ +
+ + + + + + + + + + + + + + + + + + + +
Summary of Problem:________________________________________
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
Detailed Description of Problem:________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________ +
________________________________________
+ + + diff --git a/doc/cups.css b/doc/cups.css new file mode 100644 index 0000000000..d5f37fa431 --- /dev/null +++ b/doc/cups.css @@ -0,0 +1,4 @@ +BODY { background-color: #cccc99 } +H1 { font-family: sans-serif; } +H2 { font-family: sans-serif; } +TH { background-color: #999966 } diff --git a/doc/cupsdoc.css b/doc/cupsdoc.css new file mode 100644 index 0000000000..333f20144d --- /dev/null +++ b/doc/cupsdoc.css @@ -0,0 +1,9 @@ +H1 { font-family: sans-serif } +H2 { font-family: sans-serif } +H3 { font-family: sans-serif } +H4 { font-family: sans-serif } +H5 { font-family: sans-serif } +H6 { font-family: sans-serif } +SUP { font-family: sans-serif; font-size: 6pt } +PRE { margin-left: 2em } +CODE { font-weight: bold } diff --git a/doc/documentation.html b/doc/documentation.html new file mode 100644 index 0000000000..e8803fcb5c --- /dev/null +++ b/doc/documentation.html @@ -0,0 +1,70 @@ + + + Documentation - Common UNIX Printing System + + + Current Printer Status + Current Printer Classes Status + Current Jobs Status + Read CUPS Documentation On-Line + Download the Current CUPS Software + + + + +

+ +Easy Software Products Home Page + + +

Documentation

+ +The following documentation for CUPS is available on this server: + +
    + +
  • Whitepaper - An Overview of the Common UNIX Printing System ( + HTML | + PDF ) + +
  • Software Users Manual ( + HTML | + PDF ) + +
  • Software Administrators Manual ( + HTML | + PDF ) + +
  • Configuration Management Plan ( + HTML | + PDF ) + +
  • Interface Design Description ( + HTML | + PDF ) + +
  • Software Design Description ( + HTML | + PDF ) + +
  • Software Version Description ( + HTML | + PDF ) + +
  • Software Security Report ( + HTML | + PDF ) + +
  • Software Test Plan (Not Yet Available) + +
+ +
+ +

The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software +Products. CUPS is copyright 1997-1999 by Easy Software Products, +All Rights Reserved. + + + diff --git a/doc/figures.sc b/doc/figures.sc new file mode 100644 index 0000000000..44c439ffd7 Binary files /dev/null and b/doc/figures.sc differ diff --git a/doc/idd.html b/doc/idd.html new file mode 100644 index 0000000000..d003eeb5db --- /dev/null +++ b/doc/idd.html @@ -0,0 +1,746 @@ + + +DRAFT - CUPS Interface Design Description + + + + + +


+

DRAFT - CUPS Interface Design Description


+CUPS-IDD-1.0
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Internal Interfaces + +4 External Interfaces + +5 5 - Directories +
+
A Glossary + +
+

1 Scope

+

1.1 Identification

+

This interface design description document provides detailed file +formats, message formats, and program conventions for the Common UNIX +Printing System ("CUPS") Version 1.0.

+

1.2 System Overview

+

The Common UNIX Printing System provides a portable printing layer +for UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

1.3 Document Overview

+

This interface design description document is organized into the +following sections:

+
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Internal Interfaces
  • +
  • 4 - External Interfaces
  • +
  • 5 - Directories
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

+
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.0: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.0: CUPS Software Design Description
  • +
  • CUPS-SPM-1.0: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.0: CUPS Software Security Report
  • +
  • CUPS-STP-1.0: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.0.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

The following non-CUPS documents are referenced by this document:

+
    +
  • IEEE 1387.4, System Administration: Printing (draft)
  • +
  • IPP/1.0: Additional Optional Operations - Set 1
  • +
  • IPP/1.0: Encoding and Transport
  • +
  • IPP/1.0: Implementers Guide
  • +
  • IPP/1.0: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
+

3 Internal Interfaces

+

3.1 Character Set Files

+

The character set files define a mapping between 8-bit characters +and the Unicode character set. They are named using the ISO standard +number defined for the character set. Each file consists of up to 256 +lines of ASCII text. Each line consists of two hexadecimal numbers; the +first number is the character number in the character set (0x00 to +0xff), and the second number is the Unicode character number (0x0000 to +0xffff).

+

3.2 Language Files

+

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:

+
    +
  • us-ascii
  • +
  • utf-8
  • +
  • iso-8859-1
  • +
  • iso-8859-2
  • +
  • iso-8859-3
  • +
  • iso-8859-4
  • +
  • iso-8859-5
  • +
  • iso-8859-6
  • +
  • iso-8859-7
  • +
  • iso-8859-8
  • +
  • iso-8859-9
  • +
  • iso-8859-14
  • +
  • iso-8859-15
  • +
+

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.

+

3.3 MIME Files

+

CUPS uses two MIME files in its standard configuration.

+

3.3.1 mime.types

+

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:

+
    +
    +mime-type := super "/" type { SP rule }*
    +super := { "a-z" | "A-Z" }*
    +type := { "a-z" | "A-Z" | "-" | "." | "0-9" }*
    +rule := { extension | match | operator | "(" rule ")" }*
    +extension := { "a-z" | "A-Z" | "0-9" }*
    +match := "match(" regexp ")" |
    +         "ascii(" offset "," length ")" |
    +	 "printable(" offset "," length ")" |
    +	 "string(" offset "," string ")" |
    +	 "char(" offset "," value ")" |
    +	 "short(" offset "," value ")" |
    +	 "int(" offset "," value ")" |
    +	 "locale(" string ")"
    +operator := "+" |	[ logical AND ]
    +            "," | SP    [ logical OR ]
    +	    "!"         [ unary NOT ]
    +
    +
+

The 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

+

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.

+

3.4 PostScript Printer Description Files

+

The PostScript Printer Description (PPD) file format is described in +Adobe TechNote #5003: PostScript Printer Description File Format +Specification Version 4.3.

+

3.4.1 CUPS Extensions to PPD Files

+

CUPS adds several new attributes that are described below.

+

3.4.1.1 cupsFilter

+

This string attribute provides a conversion rule of the form:

+
    +
    +source/type cost program
    +
    +
+

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.

+

3.4.1.2 cupsManualCopies

+

This boolean attribute notifies the RIP filters that the destination +printer does not support copy generation in hardware. The default value +is false.

+

3.4.1.3 cupsModelNumber

+

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.

+

3.4.1.4 cupsProfile

+

This string attribute specifies a color profile of the form:

+
    +
    +resolution/type density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22
    +
    +
+

The resolution and type values may be "-" to act as a +wildcard. Otherwise they must match one of the Resolution + or MediaType attributes defined in the PPD file.

+

The density and gamma values define gamma and density +adjustment function such that:

+
    +
    +f(x) = density * xgamma
    +
    +
+

The m00 through m22 values define a 3x3 transformation +matrix for the CMY color values. The density function is applied +after the CMY transformation.

+

3.4.1.5 cupsVersion

+

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".

+

3.5 Scheduler Configuration Files

+

The scheduler reads three configuration files that define the +available printers, classes, and services:

+
+
classes.conf
+
This file defines all of the printer classes known to the system.
+
cupsd.conf
+
This file defines the files, directories, passwords, etc. used by +the scheduler.
+
printers.conf
+
This file defines all of the printers known to the system.
+
+

3.5.1 classes.conf

+

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: +

+ + + + + + + + +
DirectiveDescription
<Class name> +
</Class>
<DefaultClass name> +
</Class>
Info
Location
MoreInfo
Printer
+
+

+

3.5.2 cupsd.conf

+

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: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDefaultDescription
AccessLogSpecifies the location of the access log +file (default "logs/access_log").
Allow
AuthClass
AuthType
BrowseAddress
BrowseInterval
BrowsePort
BrowseTimeout
Browsing
DefaultCharset
DefaultLanguage
Deny
DocumentRoot
ErrorLog
Group
HostNameLookups
ImplicitClasses
KeepAlive
KeepAliveTimeout
<Location path> +
</Location>
LogLevel
MaxClients
MaxLogSize
MaxRequestSize
Order
PageLog
Port
RIPCache
ServerAdmin
ServerName
ServerRoot
SystemGroup
TempDir
Timeout
User
+
+

+

3.5.3 printers.conf

+

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: +

+ + + + + + + + + +
DirectiveDescription
<DefaultPrinter name> +
</Printer>
DeviceURI
Info
Location
MoreInfo
<Printer name> +
</Printer>
State
+
+

+

4 External Interfaces

+

4.1 AppSocket Protocol

+

The AppSocket protocol is an 8-bit clean TCP/IP socket connection. +The default IP service port is 9100.

+

4.2 CUPS Browsing Protocol

+

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 NL
    +
    +
+

The state and uri values correspond to the IPP +printer-state and printer-uri-supported attributes.

+

The type value is a hexadecimal number string representing +capability/type bits: +

+ + + + + + + + + + + + + + + + + + +
BitDescription
00 = printer +
1 = class
10 = local +
1 = remote +
(always 1)
21 = can print B
31 = can print color
41 = can duplex
51 = can staple
61 = can do fast copies
71 = can do fast collating
81 = can punch holes
91 = can cover
101 = can bind
111 = can sort
121 = can print up to 9x14 inches
131 = can print up to 18x24 inches
141 = can print up to 36x48 inches
151 = can print variable sizes
+
+

+

4.3 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.

+

The MIME type for CUPS PostScript files is +application/vnd.cups-postscript.

+

4.4 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 Interface 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. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BytesDescriptionValues
0-63MediaClassNul-terminated ASCII string
64-127MediaColorNul-terminated ASCII string
128-191MediaTypeNul-terminated ASCII string
192-255OutputTypeNul-terminated ASCII string
256-259AdvanceDistance0 to 232 - 1 +points
260-263AdvanceMedia0 = Never advance roll +
1 = Advance roll after file +
2 = Advance roll after job +
3 = Advance roll after set +
4 = Advance roll after page
264-267Collate0 = do not collate copies +
1 = collate copies
268-271CutMedia0 = Never cut media +
1 = Cut roll after file +
2 = Cut roll after job +
3 = Cut roll after set +
4 = Cut roll after page
272-275Duplex0 = Print single-sided +
1 = Print double-sided
276-283HWResolutionHorizontal and vertical +resolution in dots-per-inch.
284-299ImagingBoundingBoxFour integers giving +the left, bottom, right, and top positions of the page bounding box in +points
300-303InsertSheet0 = Do not insert separator +sheets +
1 = Insert separator sheets
304-307Jog0 = Do no jog pages +
1 = Jog pages after file +
2 = Jog pages after job +
3 = Jog pages after set
308-311LeadingEdge0 = Top edge is first +
1 = Right edge is first +
2 = Bottom edge is first +
3 = Left edge is first
312-319MarginsLeft and bottom origin of image +in points
320-323ManualFeed0 = Do not manually feed +media +
1 = Manually feed media
324-327MediaPositionInput slot position from +0 to N
328-331MediaWeightMedia weight in grams per +meter squared
332-335MirrorPrint0 = Do not mirror prints +
1 = Mirror prints
336-339NegativePrint0 = Do not invert prints +
1 = Invert prints
340-343NumCopies1 to 232 - 1
344-347Orientation0 = Do not rotate page +
1 = Rotate page counter-clockwise +
2 = Turn page upside down +
3 = Rotate page clockwise
348-351OutputFaceUp0 = Output face down +
1 = Output face up
352-359PageSizeWidth and length in points
360-363Separations0 = Print composite image +
1 = Print color separations
364-367TraySwitch0 = Do not change trays if +selected tray is empty +
1 = Change trays if selected tray is empty
368-371Tumble0 = Do not rotate even pages +when duplexing +
1 = Rotate even pages when duplexing
372-375cupsWidthWidth of page image in pixels
376-379cupsHeightHeight of page image in +pixels
380-383cupsMediaTypeDriver-specific 0 to 2 +32 - 1
384-387cupsBitsPerColor1, 2, 4, 8 bits
388-391cupsBitsPerPixel1 to 32 bits
392-395cupsBytesPerLine1 to 232 - +1 bytes
396-399cupsColorOrder0 = chunky pixels (CMYK +CMYK CMYK) +
1 = banded pixels (CCC MMM YYY KKK) +
2 = planar pixels (CCC... MMM... YYY... KKK...)
400-403cupsColorSpace0 = white +
1 = RGB +
2 = RGBA +
3 = black +
4 = CMY +
5 = YMC +
6 = CMYK +
7 = YMCK +
8 = KCMY +
9 = KCMYcm
404-407cupsCompressionDriver-specific 0 to 2 +32 - 1
408-411cupsRowCountDriver-specific 0 to 2 +32 - 1
412-415cupsRowFeedDriver-specific 0 to 2 +32 - 1
416-419cupsRowStepDriver-specific 0 to 2 +32 - 1
+
+

+

The MIME type for CUPS Raster files is +application/vnd.cups-raster.

+

4.5 CUPS Raw Files

+

Raw files are printer-dependent print files that are in a format +suitable to the destination printer (e.g. HP-PCL, HP-RTL, etc.) The +MIME type for CUPS Raw files is application/vnd.cups-raw.

+

4.6 File Transfer Protocol

+

The File Transfer Protocol (FTP) is described by +RFC 959: File Transfer Protocol.

+

4.7 Internet Printing Protocol

+

The Internet Printing Protocol is described by the following RFCs:

+ +

CUPS defines the following extension operations to IPP.

+

4.7.1 Get Default Destination (CUPS_GET_DEFAULT = +0x4001)

+

The get default destination operation returns the printer attributes +for the system default printer or class. The only required attributes +are attributes-charset and +attributes-natural-language.

+

Get default destination will only return ipp-ok.

+

4.7.2 Get Printers (CUPS_GET_PRINTERS = 0x4002)

+

The get printers operation returns the printer attributes for all +printers known to the system. The only required attributes are +attributes-charset and attributes-natural-language.

+

Get printers will only return ipp-ok.

+

4.7.3 Add Printer (CUPS_ADD_PRINTER = 0x4003)

+

The add printer operation adds or replaces the specified printer. +The attributes-charset, attributes-natural-language + and printer-uri attributes are required.

+

The printer-location, printer-info, +printer-more-info, and device-uri attributes are +required when initially adding a printer and optional when modifying a +printer.

+

A PPD file or System V interface script may follow the IPP request +body. If a valid interface script or PPD file is not provided then the +printer is treated as a generic PostScript device.

+

Add printer will return ipp-ok, ipp-not-authorized +, ipp-bad-request, or ipp-attributes.

+

4.7.4 Delete Printer (CUPS_DELETE_PRINTER = 0x4004) +

+

The delete printer operation removes the specified printer. The only +required attributes are attributes-charset, +attributes-natural-language, and printer-uri.

+

Delete printer will return ipp-ok, ipp-not-found +, or ipp-not-authorized.

+

4.7.5 Get Classes (CUPS_GET_CLASSES = 0x4005)

+

The get classes operation returns the printer attributes for all +classes known to the system. The only required attributes are +attributes-charset and attributes-natural-language.

+

Get classes will only return ipp-ok.

+

4.7.6 Add Class (CUPS_ADD_CLASS = 0x4006)

+

The add class operation adds or replaces the specified class. The +attributes-charset, attributes-natural-language, +and printer-uri attributes are required.

+

The printer-location, printer-info, +printer-more-info, and member-uris attributes are +required when initially adding a printer and optional when modifying a +printer.

+

Add class will return ipp-ok, ipp-not-authorized +, ipp-bad-request, or ipp-attributes.

+

4.7.7 Delete Class (CUPS_DELETE_CLASS = 0x4007)

+

The delete class operation removes the specified class. The only +required attributes are attributes-charset, +attributes-natural-language, and printer-uri.

+

Delete class will return ipp-ok, ipp-not-found +, or ipp-not-authorized.

+

4.7.8 Accept Jobs (CUPS_ACCEPT_JOBS = 0x4008)

+

The accept jobs operation allows jobs to be accepted by the +specified destination. The only required attributes are +attributes-charset, attributes-natural-language, +and printer-uri.

+

Accept jobs will return ipp-ok, ipp-not-found +, or ipp-not-authorized.

+

4.7.9 Reject Jobs (CUPS_REJECT_JOBS = 0x4009)

+

The reject jobs operation prevents jobs from being accepted by the +specified destination. The only required attributes are +attributes-charset, attributes-natural-language, +and printer-uri.

+

Reject jobs will return ipp-ok, ipp-not-found +, or ipp-not-authorized.

+

4.7.10 Set Default Destination (CUPS_SET_DEFAULT = +0x400A)

+

The set default destination operation returns the printer attributes +for the system default printer or class. The only required attributes +are attributes-charset, attributes-natural-language +, and printer-uri.

+

Set default destination will return ipp-ok, +ipp-not-authorized, ipp-bad-request, or +ipp-not-found.

+

4.8 Line Printer Daemon Protocol

+

The Line Printer Daemon (LPD) protocol is described by +RFC 1179: Line Printer Daemon Protocol.

+

4.9 Server Message Block Protocol

+

The Server Message Block (SMB) and related Common Internet File +System (CIFS) protocols are described at +http://anu.samba.org/cifs.

+

4.10 Trivial File Transfer Protocol

+

The Trivial File Transfer Protocol (TFTP) is described by +RFC 1350: The TFTP Protocol (Revision 2).

+

5 5 - Directories

+
+
/usr/bin
+
The cancel, lp, lpq, +lpr, lprm, and lpstat commands reside +here.
+
/usr/lib
+
The accept, disable, enable, +lpadmin, and reject commands reside here.
+
/usr/sbin
+
The lpc and cupsd commands resize here.
+
/usr/share/cups
+
This is the root directory of the CUPS static data.
+
/usr/share/cups/data
+
The character set and filter data files reside here.
+
/usr/share/cups/fonts
+
The pstoraster font files reside here.
+
/usr/share/cups/model
+
The sample PPD files reside here.
+
/usr/share/cups/pstoraster
+
The pstoraster data files reside here.
+
/var/cups
+
This is the root directory of the CUPS scheduler.
+
/var/cups/backend
+
The backend filters reside here.
+
/var/cups/cgi-bin
+
The CGI programs reside here.
+
/var/cups/conf
+
The scheduler configuration and MIME files reside here.
+
/var/cups/doc
+
The scheduler documentation files reside here.
+
/var/cups/filter
+
The file filters reside here.
+
/var/cups/interfaces
+
System V interface scripts reside here.
+
/var/cups/logs
+
The access_log, error_log, and +page_log files reside here.
+
/var/cups/ppd
+
This directory contains PPD files for each printer.
+
/var/cups/requests
+
This directory contains pending print job files.
+
+

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.
+
+

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 Printer 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
+
PCL
+
Page Control Language
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/idd.pdf b/doc/idd.pdf new file mode 100644 index 0000000000..00c4bcb26c --- /dev/null +++ b/doc/idd.pdf @@ -0,0 +1,1577 @@ +%PDF-1.2 +%âãÏÓ +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +4 0 obj<>endobj +5 0 obj<>endobj +6 0 obj<>endobj +7 0 obj<>endobj +8 0 obj<>endobj +9 0 obj<>endobj +10 0 obj<>endobj +11 0 obj<>endobj +12 0 obj<>endobj +13 0 obj<>endobj +14 0 obj<>endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj<>endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj<>endobj +22 0 obj<>endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj<>endobj +26 0 obj<>endobj +27 0 obj<>endobj +28 0 obj<>endobj +29 0 obj<>endobj +30 0 obj<>endobj +31 0 obj<>endobj +32 0 obj[11 0 R +13 0 R +15 0 R +17 0 R +19 0 R +21 0 R +23 0 R +25 0 R +27 0 R +29 0 R +31 0 R +]endobj +33 0 obj<>endobj +34 0 obj<>endobj +35 0 obj<>endobj +36 0 obj<>endobj +37 0 obj<>endobj +38 0 obj<>endobj +39 0 obj<>endobj +40 0 obj<>endobj +41 0 obj<>endobj +42 0 obj<>endobj +43 0 obj<>endobj +44 0 obj<>endobj +45 0 obj<>endobj +46 0 obj<>endobj +47 0 obj[34 0 R +36 0 R +38 0 R +40 0 R +42 0 R +44 0 R +46 0 R +]endobj +48 0 obj<>endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj<>endobj +52 0 obj<>endobj +53 0 obj<>endobj +54 0 obj<>endobj +55 0 obj<>endobj +56 0 obj<>endobj +57 0 obj<>endobj +58 0 obj<>endobj +59 0 obj<>endobj +60 0 obj<>endobj +61 0 obj<>endobj +62 0 obj<>endobj +63 0 obj<>endobj +64 0 obj<>endobj +65 0 obj<>endobj +66 0 obj<>endobj +67 0 obj<>endobj +68 0 obj<>endobj +69 0 obj<>endobj +70 0 obj<>endobj +71 0 obj<>endobj +72 0 obj<>endobj +73 0 obj<>endobj +74 0 obj<>endobj +75 0 obj<>endobj +76 0 obj<>endobj +77 0 obj<>endobj +78 0 obj<>endobj +79 0 obj<>endobj +80 0 obj<>endobj +81 0 obj<>endobj +82 0 obj<>endobj +83 0 obj<>endobj +84 0 obj<>endobj +85 0 obj<>endobj +86 0 obj<>endobj +87 0 obj<>endobj +88 0 obj<>endobj +89 0 obj<>endobj +90 0 obj<>endobj +91 0 obj<>endobj +92 0 obj<>endobj +93 0 obj<>endobj +94 0 obj<>endobj +95 0 obj<>endobj +96 0 obj<>endobj +97 0 obj<>endobj +98 0 obj<>endobj +99 0 obj<>endobj +100 0 obj<>endobj +101 0 obj<>endobj +102 0 obj<>endobj +103 0 obj<>endobj +104 0 obj<>endobj +105 0 obj<>endobj +106 0 obj<>endobj +107 0 obj<>endobj +108 0 obj<>endobj +109 0 obj<>endobj +110 0 obj<>endobj +111 0 obj<>endobj +112 0 obj<>endobj +113 0 obj<>endobj +114 0 obj<>endobj +115 0 obj<>endobj +116 0 obj<>endobj +117 0 obj<>endobj +118 0 obj<>endobj +119 0 obj<>endobj +120 0 obj<>endobj +121 0 obj<>endobj +122 0 obj<>endobj +123 0 obj<>endobj +124 0 obj<>endobj +125 0 obj<>endobj +126 0 obj<>endobj +127 0 obj<>endobj +128 0 obj<>endobj +129 0 obj<>endobj +130 0 obj<>endobj +131 0 obj<>endobj +132 0 obj<>endobj +133 0 obj<>endobj +134 0 obj<>endobj +135 0 obj<>endobj +136 0 obj<>endobj +137 0 obj<>endobj +138 0 obj<>endobj +139 0 obj<>endobj +140 0 obj<>endobj +141 0 obj<>endobj +142 0 obj<>endobj +143 0 obj<>endobj +144 0 obj<>endobj +145 0 obj<>endobj +146 0 obj<>endobj +147 0 obj<>endobj +148 0 obj<>endobj +149 0 obj<>endobj +150 0 obj<>endobj +151 0 obj<>endobj +152 0 obj<>endobj +153 0 obj<>endobj +154 0 obj<>endobj +155 0 obj<>endobj +156 0 obj[49 0 R +51 0 R +53 0 R +55 0 R +57 0 R +59 0 R +61 0 R +63 0 R +65 0 R +67 0 R +69 0 R +71 0 R +73 0 R +75 0 R +77 0 R +79 0 R +81 0 R +83 0 R +85 0 R +87 0 R +89 0 R +91 0 R +93 0 R +95 0 R +97 0 R +99 0 R +101 0 R +103 0 R +105 0 R +107 0 R +109 0 R +111 0 R +113 0 R +115 0 R +117 0 R +119 0 R +121 0 R +123 0 R +125 0 R +127 0 R +129 0 R +131 0 R +133 0 R +135 0 R +137 0 R +139 0 R +141 0 R +143 0 R +145 0 R +147 0 R +149 0 R +151 0 R +153 0 R +155 0 R +]endobj +157 0 obj<>endobj +158 0 obj<>endobj +159 0 obj<>endobj +160 0 obj<>endobj +161 0 obj<>endobj +162 0 obj<>endobj +163 0 obj<>endobj +164 0 obj<>endobj +165 0 obj<>endobj +166 0 obj<>endobj +167 0 obj<>endobj +168 0 obj<>endobj +169 0 obj<>endobj +170 0 obj<>endobj +171 0 obj<>endobj +172 0 obj<>endobj +173 0 obj<>endobj +174 0 obj<>endobj +175 0 obj<>endobj +176 0 obj<>endobj +177 0 obj<>endobj +178 0 obj<>endobj +179 0 obj<>endobj +180 0 obj<>endobj +181 0 obj<>endobj +182 0 obj<>endobj +183 0 obj<>endobj +184 0 obj<>endobj +185 0 obj[158 0 R +160 0 R +162 0 R +164 0 R +166 0 R +168 0 R +170 0 R +172 0 R +174 0 R +176 0 R +178 0 R +180 0 R +182 0 R +184 0 R +]endobj +186 0 obj<>endobj +187 0 obj<>endobj +188 0 obj<>endobj +189 0 obj<>endobj +190 0 obj<>endobj +191 0 obj<>endobj +192 0 obj<>endobj +193 0 obj<>endobj +194 0 obj<>endobj +195 0 obj<>endobj +196 0 obj<>endobj +197 0 obj<>endobj +198 0 obj<>endobj +199 0 obj<>endobj +200 0 obj<>endobj +201 0 obj<>endobj +202 0 obj<>endobj +203 0 obj<>endobj +204 0 obj<>endobj +205 0 obj<>endobj +206 0 obj<>endobj +207 0 obj<>endobj +208 0 obj<>endobj +209 0 obj<>endobj +210 0 obj<>endobj +211 0 obj<>endobj +212 0 obj<>endobj +213 0 obj<>endobj +214 0 obj<>endobj +215 0 obj<>endobj +216 0 obj<>endobj +217 0 obj<>endobj +218 0 obj<>endobj +219 0 obj<>endobj +220 0 obj<>endobj +221 0 obj<>endobj +222 0 obj<>endobj +223 0 obj<>endobj +224 0 obj<>endobj +225 0 obj<>endobj +226 0 obj<>endobj +227 0 obj<>endobj +228 0 obj<>endobj +229 0 obj<>endobj +230 0 obj<>endobj +231 0 obj<>endobj +232 0 obj<>endobj +233 0 obj<>endobj +234 0 obj<>endobj +235 0 obj<>endobj +236 0 obj<>endobj +237 0 obj<>endobj +238 0 obj<>endobj +239 0 obj<>endobj +240 0 obj<>endobj +241 0 obj<>endobj +242 0 obj<>endobj +243 0 obj<>endobj +244 0 obj<>endobj +245 0 obj<>endobj +246 0 obj<>endobj +247 0 obj<>endobj +248 0 obj<>endobj +249 0 obj<>endobj +250 0 obj<>endobj +251 0 obj<>endobj +252 0 obj<>endobj +253 0 obj<>endobj +254 0 obj<>endobj +255 0 obj<>endobj +256 0 obj<>endobj +257 0 obj<>endobj +258 0 obj<>endobj +259 0 obj<>endobj +260 0 obj<>endobj +261 0 obj<>endobj +262 0 obj<>endobj +263 0 obj<>endobj +264 0 obj<>endobj +265 0 obj<>endobj +266 0 obj<>endobj +267 0 obj<>endobj +268 0 obj<>endobj +269 0 obj<>endobj +270 0 obj<>endobj +271 0 obj<>endobj +272 0 obj<>endobj +273 0 obj<>endobj +274 0 obj<>endobj +275 0 obj<>endobj +276 0 obj<>endobj +277 0 obj<>endobj +278 0 obj<>endobj +279 0 obj<>endobj +280 0 obj<>endobj +281 0 obj<>endobj +282 0 obj<>endobj +283 0 obj<>endobj +284 0 obj<>endobj +285 0 obj<>endobj +286 0 obj<>endobj +287 0 obj<>endobj +288 0 obj<>endobj +289 0 obj<>endobj +290 0 obj<>endobj +291 0 obj<>endobj +292 0 obj<>endobj +293 0 obj<>endobj +294 0 obj<>endobj +295 0 obj<>endobj +296 0 obj<>endobj +297 0 obj<>endobj +298 0 obj<>endobj +299 0 obj<>endobj +300 0 obj<>endobj +301 0 obj<>endobj +302 0 obj<>endobj +303 0 obj<>endobj +304 0 obj<>endobj +305 0 obj<>endobj +306 0 obj<>endobj +307 0 obj<>endobj +308 0 obj<>endobj +309 0 obj<>endobj +310 0 obj<>endobj +311 0 obj<>endobj +312 0 obj<>endobj +313 0 obj<>endobj +314 0 obj<>endobj +315 0 obj<>endobj +316 0 obj<>endobj +317 0 obj<>endobj +318 0 obj<>endobj +319 0 obj<>endobj +320 0 obj<>endobj +321 0 obj<>endobj +322 0 obj<>endobj +323 0 obj<>endobj +324 0 obj<>endobj +325 0 obj<>endobj +326 0 obj<>endobj +327 0 obj<>endobj +328 0 obj<>endobj +329 0 obj<>endobj +330 0 obj<>endobj +331 0 obj<>endobj +332 0 obj<>endobj +333 0 obj<>endobj +334 0 obj<>endobj +335 0 obj<>endobj +336 0 obj<>endobj +337 0 obj<>endobj +338 0 obj<>endobj +339 0 obj<>endobj +340 0 obj<>endobj +341 0 obj<>endobj +342 0 obj<>endobj +343 0 obj<>endobj +344 0 obj<>endobj +345 0 obj<>endobj +346 0 obj<>endobj +347 0 obj<>endobj +348 0 obj<>endobj +349 0 obj<>endobj +350 0 obj<>endobj +351 0 obj<>endobj +352 0 obj<>endobj +353 0 obj<>endobj +354 0 obj<>endobj +355 0 obj[186 0 R +187 0 R +188 0 R +189 0 R +190 0 R +191 0 R +192 0 R +193 0 R +194 0 R +195 0 R +196 0 R +197 0 R +198 0 R +199 0 R +200 0 R +201 0 R +202 0 R +203 0 R +204 0 R +205 0 R +206 0 R +207 0 R +208 0 R +209 0 R +210 0 R +211 0 R +212 0 R +213 0 R +214 0 R +215 0 R +216 0 R +217 0 R +218 0 R +219 0 R +220 0 R +221 0 R +222 0 R +223 0 R +224 0 R +225 0 R +226 0 R +227 0 R +228 0 R +229 0 R +230 0 R +231 0 R +232 0 R +233 0 R +234 0 R +235 0 R +236 0 R +237 0 R +238 0 R +239 0 R +240 0 R +241 0 R +242 0 R +243 0 R +244 0 R +245 0 R +246 0 R +247 0 R +248 0 R +249 0 R +250 0 R +251 0 R +252 0 R +253 0 R +254 0 R +255 0 R +256 0 R +257 0 R +258 0 R +259 0 R +260 0 R +261 0 R +262 0 R +263 0 R +264 0 R +265 0 R +266 0 R +267 0 R +268 0 R +269 0 R +270 0 R +271 0 R +272 0 R +273 0 R +274 0 R +275 0 R +276 0 R +277 0 R +278 0 R +279 0 R +280 0 R +281 0 R +282 0 R +283 0 R +284 0 R +285 0 R +286 0 R +287 0 R +288 0 R +289 0 R +290 0 R +291 0 R +292 0 R +293 0 R +294 0 R +295 0 R +296 0 R +297 0 R +298 0 R +299 0 R +300 0 R +301 0 R +302 0 R +303 0 R +304 0 R +305 0 R +306 0 R +307 0 R +308 0 R +309 0 R +310 0 R +311 0 R +312 0 R +313 0 R +314 0 R +315 0 R +316 0 R +317 0 R +318 0 R +319 0 R +320 0 R +321 0 R +322 0 R +323 0 R +324 0 R +325 0 R +326 0 R +327 0 R +328 0 R +329 0 R +330 0 R +331 0 R +332 0 R +333 0 R +334 0 R +335 0 R +336 0 R +337 0 R +338 0 R +339 0 R +340 0 R +341 0 R +342 0 R +343 0 R +344 0 R +345 0 R +346 0 R +347 0 R +348 0 R +349 0 R +350 0 R +351 0 R +352 0 R +353 0 R +354 0 R +]endobj +356 0 obj<>endobj +357 0 obj<>endobj +358 0 obj<>endobj +359 0 obj<>endobj +360 0 obj[356 0 R +357 0 R +358 0 R +359 0 R +]endobj +361 0 obj<>endobj +362 0 obj<>endobj +363 0 obj<>endobj +364 0 obj<>endobj +365 0 obj<>endobj +366 0 obj<>endobj +367 0 obj<>endobj +368 0 obj<>endobj +369 0 obj<>endobj +370 0 obj<>endobj +371 0 obj<>endobj +372 0 obj<>endobj +373 0 obj<>endobj +374 0 obj<>endobj +375 0 obj<>endobj +376 0 obj<>endobj +377 0 obj<>endobj +378 0 obj<>endobj +379 0 obj<>endobj +380 0 obj<>endobj +381 0 obj<>endobj +382 0 obj<>endobj +383 0 obj<>endobj +384 0 obj<>endobj +385 0 obj<>endobj +386 0 obj<>endobj +387 0 obj<>endobj +388 0 obj<>endobj +389 0 obj<>endobj +390 0 obj<>endobj +391 0 obj<>endobj +392 0 obj<>endobj +393 0 obj<>endobj +394 0 obj<>endobj +395 0 obj<>endobj +396 0 obj<>endobj +397 0 obj<>endobj +398 0 obj<>endobj +399 0 obj<>endobj +400 0 obj<>endobj +401 0 obj<>endobj +402 0 obj<>endobj +403 0 obj<>endobj +404 0 obj<>endobj +405 0 obj<>endobj +406 0 obj<>endobj +407 0 obj<>endobj +408 0 obj<>endobj +409 0 obj<>>>>>endobj +410 0 obj<>stream +xÚíßoä8rÇ¥nõË<ÉÞéwº= $@ÆÓö¸go€ h“y+Iòäa±;{Ùà²{73—àþûô/wë)U)‰ò™ ì®mªÅXüV‘,ªÿòêZ¬6ÿ\‹ïoÄûâ§ÿyu/_ÅòÕ_ÄûÕ®¾ßýñý‡W+ñ‡W7âææúêvWëÓ»‡ì?Þ}z—þë½XÿójWÞïʇ]ù¸+»òîü˾û$¾}ùëçwÿ.nß_¿û7±¾¾~wâV|z|•?Ï/\fE>Þ,‹‹³mÙüÏâöqì\òaqzªrv~ù8N.ys¡F*À-nGÆ%oژžÊùe<.<Ôív \¹ø‹Øq®ûÐã•óµÃ\7\*›æÎô•Ý>³Ìõ <óò]ìWváY)þ¥S\7žµ2Y;Ã%…g³\:Âe¬v»Ì—¼ð¬ÿÍà\YèuQ¾˜ëÞë¨Lâ!¹®½ÎŠ¿ŒË²Z·±6åÍ \2ô<ÁÀI!,—×½sõ‚Ń`qÀ` X 0pZ2øâãÀò¼eO\û-3Íæêk÷Áµòz/“¸î¼Ê´s®Ô¤¼î˜+ ‡á"ˆ"¸¯ð,í€1H!C;`$šAbt®Ì´¬»â +‡åB1Cæx1‡ç"‹=‘Kåùp ¸¼À:Wê9Q֖¹dè×Ä2×Ês¤Ì­r¥ž3%¶È劢œ+ò*kk\™KX­Òã TÔ# LÔ£Š4ðZåJ\Ãjé0ŸÆ£: F¨ñçŒã’.b5Æõ0FGŒ0ŸKF0读Î΋7Ûr¿=øÐm‡A/Ý埿©òí9ˆÎ: ºï.¿!é_>\tÓaÐuw·N•î Ж\«nºªØk ëa=tØ]„ôcÉÍ ^³¹Ø¡-]œI6årqC zznƚ2ÄL.fw±Ò©9]0¹X<7’Ñe>+éFÛ-vْÅöeƒGoZ‘z°¿ªa’öÎI6X3¸DoC‹Ÿyй²°È`>‹,ò¾#’ÂX9š¹Â"‚M©\ÉFÈ1ŘÈ%†Â"‚Íi\™É \؛x½Î­–ÔÈÁZ$o‹tújNáJ,„3Feeps°¤~lŸ‹Ð‚Ï%̓4Ӓñ Qσ®}¹c"X™¡LòŽŠà"ؐÙNm0̱\ÑP™'Ê,Á §y‡Eð ÌͰ;+¤hâǵr + - p\h!M:|W:°Gf(ØÅWà ï¼à$l†á +Ý ŠÖO\)?0®Ãâv®ÈÑ tز+tDãIí Z¹R·º Ùa“V®È±îBú°¸+t¬»OzÞ•9ã’iM +Z¸çº %NZ¸„c£ -eq#—t°»pc~Ùȕ:Ø]¸e¤ ‘ ©ò~¯X(+š4r…E†Dåhâª|ÏX¨á±nàBª|Ð7WN²!àªüºw.„!N¸X[câDϕº(òhA‹µ\à¢È£ÐRË%U œ)Ít\ÒUÕÀ ý©Ž+¥…†eOvú©bìO¿‡Ã3MJªœbýü +ß0`Qs×\Ë%K7jJh%ºÖXÃ%h±F#×TËu¸MQç0ŽCâp†W€ãòô\PP¯ n +´%gx-‘\K-WVx>€5CÌ( Ô\@t^Í\–ko{“S'L,)ýDÍ%ˆÎ«™k¢ç:i…¤ÌzÐÏÁáËõd\ +®“¶§x3Ä(}¬âʨ1T ×\ËuÁˆ²V’`:Ðç^žkªçŠžQH™|gXAò\»Ê·pyz®ôðYÅ %Pq…D3låZj¹ö÷ší…_²k¶©‚KRͰ•+Ðs­ö@¢¾‡j´Üæ+¸Rª¶rùz®ý͉Ӄ)ˆ@öÊ1–kz¬­äÚÇuå!Õ+Or,×,|’'%WA¤(³T³' ÊÆÏ==5W𥶆ˆ³WF6Ãf®´„S㒬Œ§k@”IŽç’Of¡æ:ši±$õˆså€Àµkx çJXkv8¡¢l,)\p¸†K²ÖìZ[Yãb¤/6seQÐpšH\³‹PMšlLr +W~Pzp6œ”IM6f4®ƒÒë¸"N¥(O4ÙXÒ¸J¯ã +9ãK¢ž=p7Q\¥×p¥¼=Œ#Ù@Š6&D®ƒÒk¸"ÞbÛ󟖹$cxµrí•^Ãò6g"ÌÃ’l,©\{¥WseÌ]Œ㘁´¶‘S¹öJ¯æ½˜ERe®ˆ1¼Ú¹vJ¯æÌ̉qÌ@‰¢:×κ#ý¼rÁ0Ä6[—¸X›ÊåØJÁµk½Pqíí^2Bh&P¢¨Xýè⢁øe®S#ª\b¯É‚nˆ+DÀ¬,‚2ײøhª\ ázê(Ân +vfVäB¬ÙL5&1/*ê¤Â•i¸’OF7Ä!@Ã¹Æ$¦õªëŸu®ÕÓC@ïV¢=m‰Kpd£´5, ¾¨À)¹ä±+²!J„]!:ԚDPXV¹R%Wr¬œÐc_„>:œè}ÿö•6×Eͬù©*×ê¨1’žoâ¹2ŽW>ÝÂ?+Ã+âŠ2Wá9öí"à£Ã9ƗÌê\‰‚«˜Š‘ qÕ>`/‡kŒ6Åu®LÁUԛ”< <׊%5›˜æu®ƒ­–¸Ââ€%OÂäcs)p –lTæñôžb^\ä*gD­:ÈhzªX¥Ü©<œb£È• ;é õÐr¨üÞkò&WrÉWX²¼¬ƒTM@G½z;Év/>õÏ{8BJåJ˜røTöƒÕ=®öhÞÏGU+ó“Qr ^å;™ßs¥ÏNæ±\£ùâ$pnÙýh^î¿­ä|]àŠØ2_¬s¾VýÖ;»,-ûV{kÇù”ÑvÛEšEÀ¹å%‚ë´nSœ±’kÎᚫ¹Š#éõ‘K°Ý—_£:•&N9\S%W¦Þ_ÙîK  1ãJ=—§äê}þ¢Ú^u¹©•&.9\KWRW9@¹å –kª _–*®€Ã(¸Âúc´Ìµ7X]î\¥‰פÎõ$þYx´{@¹å͵Tsù*®êq>Wí àQηþä!<˜ ŽkÖȵû¿á•Z0+;–XÅ5Wº¢r<Џ¨èdž6ÛnÌÛ¹/ŸÖvî¼Òñ€b§®ÚEiÉn¨Eì%‚«–RîâSnOµ‰‡«vQyÓéÇ¨0já:¥)²ägÊ&.9\ՋD90ßѐÏ6sI W¤ç +8\Ջ*#eg–@…Q9†ëôƒ"û_Íås¸*UžJ<—ß—â8_;—⢴ê`›r ˜ðpbÎU× Åq¾v.ÝÀ@5_öìpI ×J­óŠã|®úE‘ÒÁ&Œ +r= 9·å&֏ó!¸ê ¥#BqÍP\©Ú¥š8JqœÁU¿H˕Z⊔ñÆÃ) ©4±~œÁU¿(T:"×Ã%½š"7ÎSÇù0\µ‹´\ ?Œ*´áðKô¼RqœÃU»¨XýtG×:7œ͕M¬çÃpÕ.Òr?ŒÊÕ£YU­5ñ Ú4®êE\9š+Pý֏5M¬çCqU/ÒrE¹Öê^ŒÕM¬çCqU/Òr­øáa®68Íò~­‰Õã|(®êEa%MõÈ%¬qù±†«ª–šX9·ãª\Äçš ¹üeá·¿|Xö˜«›X9·ãª\$ +Š]â +ípò‹ñÆ~Ù#P7±rœÇU¹¨G%X® ÇÍSrWáýPŠ&îD›ÊU¾hUˆ¢—×-WÚÄU>·äRœ,6q…åšqeºxþT +"Wù¢¤:TÂ=—ì˜KjNq(Žó!¹Ê¥ɖ–knĕ7r‡«t‘¬„æ‰\‡«|QX`âÀ՞{¸ì«tœËU¾(R$ão¸Òa¹"Wé¢ä´«|Zäœ+åp•.’ÅV¦ÇxÃdZiKr¸Ê‰Óþ×½GàŠ»ä*çCs•/Jjû•.p%®òE•HPì¸L¦Ë(®°™+ãp•/*όƒ•\…ã|x®ÊE¥‹£¹Öú&F®òEå4"Øqµ.oø†\Â+.ÑÎÔ?•«rÑ]q²˜ôÃu|€¦‰’ÃU½è¾°aËò°Ë?üîôþùV®±äÀÊâ™Ah_f]nïžK¼p½pkúL¹‚qr…/\/\/\/\/\8®Ù × W÷\ž9×fæƒ>WJ©;,×ýîfþ%¦¹”ºs]T¯•_6TxÜ¢®z7@½Så)Ji[gÌ%jéå<ýâöT½.ƒk]^ íˆë®>£)¿Ì+;mvÜaNTµr-Ë´.©ØQ*¿Ð09.ñKÔÉ£V®y\ šZ‹â«¤oTê2¸fyihvê¶Ê 8ÂRšLµ.ƒ+([J'\ÙÓÆÓY±nñÕµ§Ýze]פtën¸’ãF¡¼.Ü´ §ì +e]>WÚ%WTر^¼KÁe’Ï5uUËü껖·w’.¹DA äiT4°ðBfM]—Ü>Ý âIg\aqNT”þdº™WKúáñÏÙÙ¦Ì bÎHé뒸¶ç¿ŽiÞ)×D÷‡-O!©¸i©Ï%ƒt;„—q…ºtœÃžrV€ Rwð\«Ãçm?yÝ×>\kâÆIii뒸¢ƒ m-=îŒë°×y¾VX»LŠ'9×Ö%qÁ)ûÕÏ;ã:†èµÖî¿ø!,øb}]%W=±sG‘ÆëÖ}uÇUÈ©´6zò6G_¬¯KáJ°Ú~°WÓ¾^±^é½ÄI=‹V[—•~ܺeC®¦}ØHyŽ£49Ž[ëR¸¤w|!ú¬™ËhYj3KE-«E_—À•óî·ÝqU²hý¸Ö“¢.…kï˜wn¹K®Â‹¶Êª/™ÓÕ¥písºóñ]r=„­åR©’Mëâ¸öŽ9ÝÕ7ãjÍûºU£F(Šº.Þ/ïÜ`¼ý·ßÂe#Ÿíá¢>©I4“U]W²³À[îžëÔÚi%”Z£ê¸öŽyç–ûàz…‰vÐ4Õ%píóÎ-raß-š6‹AS]—|òb³¾¸N‰×í\•º®½cދd#—I>ööU2˲+Ör5Õ¥pmLp’ÖO;á*»Wh]ìÔÕ¥pm$ÃO÷ŽÑ+Æ­¶p5Õ¥pm{:ñŽ/ªëŒkR²-¿‘KW—Âûð~—ɹQú³hÔù¦º®d²fbεlž~͋󐩖«©.…+=9õθ’b®*·©4¶©.…+;͹LÎ!î¯õoO›ZK-WSݖx¾ô¶-YÞ4àš·îÞ6!õ“Ŧº®Â{a»ãŠæjU®†º$.ã2:—5T­r5ÔepÅæ\3\ºM5ô¯Å*úº$®¨ö›¸2½ÂÔ¸2îzT™ŽO¥‘Ëèý嵘×y#—¾.‰K÷~V»\…Æ^æ-\Úº$®ôèӛ¹Œ²·Þè"Ôn”˜Ô5*†ïí9Ê×ëõóU|†ïYr¶¾녫®ö×-“+ú»åŠGÉÕ¾À±%—É„ù…«.£‰å¨¹f£ä’·\Á(¹Ú'`ÓgÊ5'Wø _Ãïãxá€kõ _Ü÷ø,GÉϔ+y†¢á÷š UÚ^ö:7üº¡J[“—¸ï t.Jìp9HµI]lø½œC•ÅŽ.àh %°ß{ëZÀ!Úì ù=Å®­´…mz€ü^i×Åc 8d«¿E~¿¹cGŠãÝ÷Ñ'­Ý˜hË9Ç ­Ã0æêœc^µÊ`äÅ9&ZÝ`܁s,lí@ñ»æÀÚÃ>@Ù«c,kW@é‹c3Ë´]½ås`I{cõs`Q»qÊ`›­Ú£>@őŽ90Ñ.r€N·„ÑVÀ9:§„>CØàzÖ)¡OZ8…qJ褮ªSB!š +È®uIè´9]ŠèÃv÷õÄ%G$ô#ݐc…~69\¸Äx1ÁŒ@†\ b„Q8ȱBïEý"W:ADäh¡w$BÌPäh¡F"‡³"Bè@Ùäh¡wD8V(´zº"!böUàJFIµ +Á~+r¼Ð£I™ !ô“QÈFPæB,Ýø£Y…KŒC8Bœ +þA8qHäüá:!)ÒËá +„#B¶r‚ :°˜ÝªÓ*BðÌØå +È)‚8sx-k\Ñú,(ÖCéÑg­!' ÇÐ ýŽÈIÂ1ðkôS—p~€áï€d¼C°z @NŽa>r’sx€¥ø©båa÷H*:pˆH؇œ(0Ê&ÐúyÐ9eˆ¹ÈDr‘ƒ²Ôā9 Òg”AĞPéI+Ò@½t8¥”¦UI[m“$MêÐ̶4Õr­Ü5DÚò äô6wÔ ‹±]ú@†˜Ð È3œ qE{Þ@·âA QCW Oq†1Ąø¸!g °bDAsX࢖fÀy0ýOVêÆœ3ÀzŸ5 ªšAÎ`='Y¦dï9k€õìÂ"òØV—÷¬’Þ"` ў•ƒµgºÝwÌ!è#8Ë#=Ç)À€7H{•úcÀóñô(õ’ó˜û9ý‰Çñw˜ö×a¬á\Yí­Ãp­™!¸JßS‡…¬g üê§Ã˜aðGj?òÂ:`;Â~:,a:SàKP/ArHä8®léFwM‘\©#&Cn¹‘!V¾ji˜PC5˅ÜÌ;8K¾Õ@nfˆj=öéÎÑ\xCìP:R›ÜÔýx`WŠ˜ l—–xçñÍPË%½¡-13’.ȍ ±#MF>ŒmGÞm…ê•10µÝxçÌÐZÀØ×w2Ädh([`ã‰ÙŸ±¬L)X¸ö½Ø=áÆ9•+!u˜Mí hV@æ’Þ@`24`ÇÈm‚Iaá¦`É,T¤q=gpÑî°)ßõ,… ¡XX](X…¹*^Û1°1_µFÃÒÇ`e}¡àNÖ}bé¥ +lEiG°7=)aóf0XÔ&Sõ c5œF{žÿd<[ÌBê6WrÀªßtŽ*7ôÛ¬ù\ ‹Ëóo©Å°ø¦8 ‹ÙažwwÜYÍs£V®Èãü—Î?Ö0ÎM¸¤Ç/ç(kÌ.xŸ¾4â2è°í8»l3Ç&UËô¡Ë¤ÃöhúϾ ٟ;7ä¢NÔyùXë7ù°MWnʕyvÊÙùb±xó¸)‹ÅEhøisc.f½´å?b¸¤ƒ\s \f’8Hwá¸Üë°¥.ç:¬}é Ç%ÇÖ]H.®M± ‡äÊC—¸Öö¸Òquš‹µÒёÆÇ6¹2g¸æ¹M.g´·½ç’áX4žÆÅ]Â@4h\NHv¿—Â%Gc…4.,½uHâÜñY4®l$VHå8þ%l`¹µDJî •kHïLÙ~¢r ؓ’æÈ\ƒ 1ZÚ k !FL,cp 3Ĉ{» ®A†5ˀÃEIB3Ø\½k=UŽÇÕ³v02™\R¸+…&\}Š"+u˜ËÕ/“ŒÍÅHûéÅqsõ4cž80àêÃ?û܃&\ݛ"?Kӈ«k0ƒäS3®nUÑ$Yؐ«Km”mÊÕ˜Y2¾19‡º£‰‰}®.¦-†éêv¸ìË¢ù¹ +\¹´k‹—æ-²Ãµ±E{]6YçîpåòβÉe©ËÎ×¹k\¹¼1–Á7¶Úb“‹ŸZ} º´×»\éՈÔí!¹¸dv©ºà␝¿±Ý†.¸ˆyñþ¢ƒ÷\tõ)¸ìxÿü¶“ÛwƵ뵃<[ùåǟ>‹ÇÏ_ýãoÛÿüôå×?ûõ÷ßþQþ÷æ3nÅõõö3®?Ü^½o¯ß_Ýl?e{õÛOo¯¯Vۊo¯×WÅۛû›Ä?~ý›È~ÿåÛÿýøå³€/¿ÿüן¾}ÝU¼}¿iÌés~ÿóß¾üúÇÿú¶iêÇïßnþõñŸÄݟþ$Òí/¿Šôó×Ï_þ÷óÏÛKc¹ûÇó;endstream +endobj +411 0 obj +6325 +endobj +412 0 obj<>>>>>endobj +413 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +414 0 obj +31 +endobj +415 0 obj<>>>>>endobj +416 0 obj<>stream +xÚ¥U[OA~çWœø¤‰l]nBßTԐ¨Ý +š>ð2ÌÎÂèìžufJ}ÏÌ,B©5š†DâœÛ÷}çÂK#†úÄpڂvxÞ8Ÿ4¾\ À$#Kï´“ô0†1ÇRMž‚µõƒ½ÙíGÁ#Ša”ŠÂÊLrf%Á¹q\»¶QϹNҀ,¬ÐãRaä¼p_\ËÒEBмÊ)”—’,dµL*‘BF!C3kŽ!ưùÎ+R4×,wõ©j܎Z®*Çbéàaaœ;؅€ Ìs*÷p7ú‰&H²˜Ãxm¬ÈazxpñŒ¦Gð(´q°âè$zCâUKÐÚ[ +½”bõŽïW%ΠDmٌX—ÅÖB{.vÚêö€š£™7ŸÀD0²°`fO…™Nê¥P‘Âl —̬aŒ™]1-¦·,: 9ZAŒ%]™N· ªÊ·Ê¡`J$pŠÚ¸.ìÕ­ iStË͵ æûè;w.ô³Pb œ¤¡‡¦’…ØŽŠ‰ê¬­^Pܧ£Ô!ÕÈùÂnÅ$69*jæèrrÕ% µ“÷32Œ•bsçïéÁÎ<x©DEEšµGçÆáòe¨C&\§‡7Éðî¯.âøt0=:†1 Ùoë!=WȟÉm|{ÂYYŽéQøI÷P©2µ)ƒ{%MUºI ¦­¤]€Ô'·UÁ]#˜’vý¦>,M ,+Ôρ!aši\GÙ¡HÐØ±_¾-§m¤MH’!-B“$;C€eX'û¬’) º*V–ª> ª"axßFLì©ë\Uaxe,æòÕ^Ö«ˆ\ß=Àõb }zÈ+­iÅÕPÌþöêD'íéÑ^'+@æþ–¸ s?JhH˜Nï3á†,u;±aV`Ñܑ­–Õ¼Ú0ܶˆIrD=g…ˆBЏw†JáÊïªðb¾†b¼.ÖêùWá§­Þ)ü‰†®~s÷îó-ʍpoEQR¸™ VÐÊ~*´M¡a‹inF¯kÿ©Êqùóÿrt)ÇPjÒ µüdìÅ^+¤•×ë`êצfP<îîÿ¤vú'рòºW÷ÿå¤ñ½ñ…KZendstream +endobj +417 0 obj +837 +endobj +418 0 obj<>>>>>endobj +419 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS046V072PIÑp rt QÐUp VðÌ+I-JKLNUpI-ÎLÏQÉE™%™ùyš!Y\º ºPF 3=30ßP!89¿ $êÂȐV!õendstream +endobj +420 0 obj +120 +endobj +421 0 obj<>>>>>endobj +422 0 obj<>stream +xÚ­•AsÚ0…ïüŠ=’™ØÁ†`Íé0S&69qQ­5¨cKT“òï+!C ¥âf|°Á«ï­´ïÁ÷Vs…ÐíC^µ>e­‡§È +ó¦õ £íX Dž£ºË¾¹’G?vEÞcì»2?€ñ2Ia"ò]…\Íw zuywà÷my¶A(DYŠ7Æ×n!=_L<êRøº½1_k†œ×à0öCð¾keö#¸Tn[o>>>>>endobj +425 0 obj<>stream +xÚ-‹Á +Â0DïûsÔC´›”êµZ Þ´® q#ŒšöÿшÌÀ03¼71ª¯®)öÚ-û5˜!ìV¶‚\gÝÐöƒíùpÂ>MšÃÅ+:ã-•ð9¾¦øLs¹“) ù“uYjˋ¿n1hЬÉëX®Ð‘>H.#ùendstream +endobj +426 0 obj +123 +endobj +427 0 obj<>>>>>endobj +428 0 obj<>stream +xڝVÑn›0}ÏW\õ©• + $!d{ÚªVŠ´j›Bß"MޱO`˜m¶t_¿k „ШÝP_\¸çÜ˹ǧý9 `Š?,C˜E@óɧdòîaÁ +Žo¢å’ôzki˜’$sN(Ó7ÉW»ðcWí-bßÕû܈"‹aà <ˆ¬EÌ!šúÙʏl}r`@»zõÜÖCʸ ä¤,…ÜΙߌIˆ½0'ˆ"S0Èò$-Ò›ØàˆbvìÌüÐö•$g)TÚR[ôzó´A.¢RU¾C¼›!^¨ºfÀ|O衞h!µÐFCÁ¡*Á."Èl :ÜÜ­×`ر¥°ugæwv$)£"GáÝ8úC=J›vB¡ƒµÏ¥}>h|.óözzœNí¬Ó#çۛÛNHÍp˜tÐ⥺Í{Çsb²\þƒàƒ„ð™È}Eö켑µ¥g¶°á‘T™¸Ç~A5³ŒQ# +Yë‰ZCδFí´!¦c~Ã"»g(v=¶NÑFÙã­JýýÊ~v½UHS7ë­K\!µLÌßû ŠÉ«ÛæÈ™¡þöfÐþ²½¬7Ўy¡Xg0èYª! #§vÒ9¦v™H™4v ýÒÐöKv ¯DÏñ­hµF@+¥Ÿ=ƒB‹ì¥øƒ¥¿HV!Ê÷Þ-’6‹ cüŽnm-á|Óוöˆ¦Bœãz\îÅÿ…ºðâx±ò‚q°pl66[ŒƒEã`Ëq°‘{[\÷H)ƒZKÏù·ŸEM0ڈÑ¥Œ¥6Ü-lƒ©5>¬yÿ¹·¨(”¥.\H¤·¶òbl»[בœr¹*SbXÚwMO¸½Ïö×^!Þé×3yëÇû7òøîéëÆré:…j€KeŒTñÔýýD™¸ØWŠØnÇ'¾8~õ?‹y<õWX‡5õ&î“É·É__ˆ–endstream +endobj +429 0 obj +717 +endobj +430 0 obj<>>>/Annots 32 0 R>>endobj +431 0 obj<>stream +xÚ­WËrÛ6Ýû+n™Ò†4)Éòc¦ 5¶;^Äqcµ‹Æ]@$(¡& …€ì8qÿ½ç”E1²2îTö"qîëà> O{ ÅøKh0âÿ´Üûe²·~LÉ êÓ$ÇÚè(á¯Yo ¢„JUÊÈ>,¤y=ùÐ!%‰†ƒãhÄÀÉ\¶`”«BR&sUáÁb­–©žUê‹Ìüš‡‰*£TWFkHçðI×TêZRá$ñj|ýö€ül#z«ËRV–€iïnÖóPcEmé^Ù¹³·ÐKè¾é¯‚›×”ÎE-R+ëˆØÑ©HoM!̜77JEESIKW…uÊ$TÁá¼"«; «ª%Væh0N°b·t }&Ò9Uº +§…¨n=Ü9o¼÷‚Þ]¼;s‘Ê®Ê܂§f¹õ>/°Ç€Ô˜“5<} +üb|9Žh\޳ާ¹. +}¯ª™ƒ¶ì`“j),‡Œ]!#kåéwËÍæY¥+ª—…4'>b:öƒ4z²±2™ð§DètœüLÎ +ö¯õ+]_9uôϏB¯ˆðK@ŒÃ?ƒ.n¥· Ã=t×È]ãðøQg։‚$‰DdT +‹½y$ ûÂ"! Þ½“àü5káínl3퍸oN¿œÉÏ oáqL«O Lªƒuži)xP!«¶}§Ü¢V•ÓBþYc!<ëú—»¹š:bw¢XÊëÚ¾\ ñ½\¨Ð©ðœ´âÙÀ>%oÕO¼þó‘ +=S¦ñå)ýµ]?›xÃ2Hñ ™÷v‰ü<}ÿHËJÔtù~â%Öm7ärk7ÞU5úåžò-r-Ðs¶ƒrlwq®º›:(´¾¥@´6ø‚Žfïu}KÓ+Ѭ3יDt‰ˆ¦j¢U*Q¡=­R§•ÚØÐ(t“|TÖ+ÊUm|£ÜœCá ï£ä9Ô÷Ýöîÿ›C¸Xíe“¨T3—èE“è…c´o æÛÉPËE- šFoô²N%ÇØq<“ á»#,¢óí#  ŽŒmêë¦óœK☧bdÏ'-j=«EÉë¤]ä[r¡ƒÅª´%³)G–AråF¾Ä<[ÏhEÊR¹„ˆDpZ2èíïW×+û™ÂF£xÖIu­seè“jHWˆç:­ÕÂÒwJȞJã^0)çÈ—lg“½8ŠqnâK—¿Ò Ž‘u T©¤’õ°y*èڟªÖ)š$ÍNsŠ~ÇìMïêê¬úÕ5 +’éÉd +jòó^µü€W‡G|íÕ| QÒ0éãÄ· ßFp 7£îˆÔ³'¢Æ™Æ k"Óù¥Fõ¿:ˆãÁI‹“gCÃò­Ï­€|”îᙸր’ŽFãt Pâ>bwÀÛà‡|^މo!JêãïÄ·À#evã[àÐ0[xÞ<6u÷\¢£ö]¦]û +L}_ø=†ïÃhàê÷ÉtÜlnowã"Y\iž­K†Û|]][[¹Y†Ž*ï0‹ Ÿ{É1¯§Këú9œå¶´®‹©Dójü9jT&ƒ~ÐGnܞ~ŸO(ô]0 ¹@k˜ImFXGÈ¢áa?fÉ¿:ãç~!iÛû¥ÿ·ùendstream +endobj +432 0 obj +1236 +endobj +433 0 obj<>>>>>endobj +434 0 obj<>stream +xڝVߏÚF~ç¯ÝKI%;Øæàˆ”‡äÈI÷p-½ÒJ•ò²ØkØÈÞuöÇÿ}gvmNr¤B¬½3»ß|óÍ _G Lð“À<…ly=ú¸½}X@’ÀºÄÙÝ4¾ƒu1ÎâiœÄ ä®1¢²\¿YAÓioe‹xF¦ë0`¬r ÌâïÆYV/¢àäJ¾pm„’ ]ÅA•`wJ¥ëwáÔ ,┎EPQ’ѺÓ^C÷c£œÎù[{l8žg,¿Õ¬¾D‘ÿ `…d–îö¾•ãj^€UFƒÀ1¼_Œ7ˆá±DÈíK0®i”¶Æ[ áœBhžÛê6ž Vu€[ü¥§­ +7Ñ Ôì›Ö¾¼ˆüÿQ:‹§'þSÏÿ“ŽU÷ªܼž…Rgò, RYº)ðü¸‚€Šž™õ/Ï)êÂ.z k?RÞaË%×ÁPÈA°;¦‹=ÓÈ_ ½d®²ðÂ*ç9/Yeøµh³­*xõ›«7×$GP·ölÇ«9e0jßåPÓ¹ ýÁ„O#c˜gP›#ú^fn)ʆ_œ ì)ggIËè7¸ uÞ¢¸ùÔG¾Ò +oæÿ±Ð΃ÎU¥êÿä„é:½›Ä‹ ¿9=Zþý ®æÂÊendstream +endobj +435 0 obj +916 +endobj +436 0 obj<>>>>>endobj +437 0 obj<>stream +xÚí–ßoÚ0Çßù+NÝK+•4ŽCSU©£í„´I]ÉÞúâ&Nñlhÿûíñ«Ú'Pdì;?¾»œùÝ"â‡Mì7·¾d­‹»NЅ¬Äµ$Mƒ²â”æ#^L+^C_ÉRo-1 x\DÇ襊¦ò;Mø’cצ¡Ç½YxY£÷J1¾vžë¼‹eWn³V„Ø –‡¯ÅA”tQŸÇQˆCÔn1&q¸´¦]³vme‘Þ(:¶Ë¾M­‹ÖÕÆa//ÜÚÕ~¶¨c£òl”â÷²yk϶²F6$ŠÒÐWÜå /Ù´2Ö!A|<š³ÞFS/<¥: JÉrå­·äʊ’ÔJ~S9;\"!ø>>>>>endobj +440 0 obj<>stream +xڕ˜]oÛ6†ïý+ˆ^µQÄQ"Ppݦ –m©íÝ™¶µÉ–+Ééº_?Jç$) +ÆÓšh™òéiŒ +Ç(r¦µtãtÎóª²}×îFc‘ç0’ÕÉVõ¶¶=ö–5mUŽƒbívü{$SvÅ¥»¸cËé +Ú±mÝXöåõæ¹:?p¯Ñ_ý—ûüê˛$P&9–ʤ´ó½\& §_¢±L^ڕi,ϧÒ4Mû-`ÈÇóÉ7hêôÒ`˜ t~ö‹¦ìû˞™I#&ÒDO?ž¹Æiæ<×ßO6 ™é#kMÕôÒ¨™éDšï»ö[oç›Mgƒ%ÍÒDÑ]¦ºzit•ò®·ÇÁve•éS’²@Se½4Êrý¬zßvC@“§qBšªé¥AS™ â¢ëú`ÛsÀU&"RH]ý4ºæYò\Ôú¸ hj)¤©š^5³ "…¯Êžìzª©2™Bš*ë¥QVf)”½+»s¹ <­”0¡Bšjë¥Ñ–gàzüLMDœ¦ +zi”Fáò©­Î{–m¸ó²("҄4QÕO£j® M»®íptASiBšªé¥Q3S¦O]{>U"¤©Ž^¥‚ýÒöÃïåÁÞµí?çSà5*E"¤©¶^mùTÏÛé©«z˜ÖP6äšyBšêê¥ÁUlG~µö4o°yÙS1íÒDO?ž96Ož¤7©ÐyD¨¦êziÔÍ$„êíÝcƒs*‡ý»Ÿú–·×_¿ Œc +ŒCŽ—¾< '³K4ŽÃKã8ÄÔ³¹‡×}°• à*b#M-¶—In ÌáßÊMí^ +°ñiÒSE‘&ŠúiÍ Lb'êJºªÿ ¤O³ž, +4UÔK£hf`ú:Ñ¥ýz¶ý@æ0s€‰Š^[ÒR³rm³íæ›CجËDLŸ/bÚ|ñòbª€¸€å¸š +-£¢VQQ‹(`®o +ÜNt™r‡ÐåüfÍ®ØâÏû›¶&¶eeÙÛ×»#ûiôj<ñ +Ï”ÉØ‚Un½¸Iªö¸U¤‰ IƒÃÿ<û›iš7endstream +endobj +441 0 obj +1023 +endobj +442 0 obj<>>>>>endobj +443 0 obj<>stream +xÚ­•ßOÛ0ÇßûWœØ <4øG~uBHŒª´I¬ o¼˜Ô¡Þ’¸KÜ2þ{Îqh7H*M­¢ÈþÞÝÇç»Ë¯‚? +<´ÿ´}IF§×>P +I,‚0æ^ Éòx!«­¬æZ›“äÇè* íî1¿æ{Â(BJC|gÄcPIXtˆ©Oöêö¨9¡ïªق†Ü ÐçÚÈâ¦Ò›ui¡Å`R§JÚ©nI}îù–4‘ÅzªªJyþpJ§JÙ©n)ÇK© +©7}·N#T¦tꡔê–’pËxW˞4“ŸC[õ@ÀnuÓI M3ì²À§–•{Ça]©ÒȪöR]f}ßuÆ|âj9YÉ¿•©\¾Õª65è {WWPh ™«R6K‹ËÙ Œüm<¸ÔE!KÓnÖFTž”Y±®õ¦\Âýñѧ£û ¡i{íéJT"ÅÀ^»ÁBWµW"]A©ËñC.ʟcç·Þ;.E!-‰°¨™zÜTÂ(]ÂRU25j+!Óy®ŸäžA¡éVäé=°ÛRå㢝q ‹è˜£õò³Ë_Ðæ/$˜¼1'wújeE }E˜`».ë´Rk‹õqåø”PÚNͱyþ©…?¦*Ÿ43õl*3±ÉÍ­»â&mçoN}vÚɣx7w¹0b:µÃÜ«]OñÐwÕ7•[•Ê»ù¬'r0Gº#A6²ï»K›•™î ÊãÆ¢S¿ý5™þªSÑ_œÆ”ƒS¿˜4gý†½Û^6‰˜_NÝ–½~ÑÏþGÙ±¦X†–Sw— ڎ]adOÔ¦Pg£QwödÜö$å"æÃüâ:1\ÞÝ.`fS‰TÎ õX›±1¶†ã֒»ä“ç;yõ Òͺ^îæ<êûè-$/Šendstream +endobj +444 0 obj +695 +endobj +445 0 obj<>>>>>endobj +446 0 obj<>stream +xڍ–Ár£8†ï~Š>:I` [µ‡q&³åª­-ïÄsËE€¼f#VˆÄ~ûmIàØTª\ýêþôwKâ¿‚V üÒãl½›=~‹Æ°ÛãH¸ +`—Íx>i¡J^À¦Ä‡=OEý°û×i—^äԋeä9½GáKU½Èô§Ð°URËTnB”¶r?öB#ßĕ¼jå×ÀKˆI®!->›-ÔN˜Ê²©Îeé ‘‰=o + F!Ô[ž +¨¤Ò&NL ñz€‘ fðôcûk%ßë¼ügtÿ ?¾ÖEÂk‘A¢$ÏR^ëŽÌƒõù¬8£C–•P\‹d‰+1é1)õ“Þ¬+ô©×Ž³Ð­ã™§‡«d·Fe¢NUž`LÐµÆð ÷Èh° Œ¦rSU +}æµ±=kÝÿòò´Ù€'$×ʬ'6h 4X’;¼älÀE™á{®˜£ïE^ +x“ᯮVm0L²—êȵF“¸y) +tó7ç:ØÄݛ޼äèRRó¢Ï•€—m»&|hTýy[´…™~]67¶Ãs;ùvÊÜZp§ÃØ÷ª7^4¸âT*%êJâ4Ƙ¼Ùn¡[D+n]^ ¥»•_¹ÚMÄü‹º©LíEöKŽ& úß=+6¶õ.ŵîAœx&Òüˆû½lŽ ¶F[/%*\¨(µyIyœ¼ÈõùÑÖ÷iW¹e–.͎!dk3ºZy>.ÿñÕöeev°xÞ͈Gð@ºü|ÿ»,ôø$ÀŒá##èŠÂb÷‰Ãè"¦+ÿFmO¶n¹4ˆÅÄùk»˜1ÇDà÷n?Ü57Å»=FXيš_Ãêûò)«;Ö5²ZÂehN*L}OXȔ=|J¥k®«×9/Þù¹úú0ÆÎ.>ã{8ÂÎ>|þPwì´u—]³[ñX±ÃzŒ†˜syb՝¸§ê††Æ6½?̂ç¶T#<4 +ºÊŽó8ñO»Ê}DYSâ4úb*ŒÁíÙ¸ìƒÁã +iÆ`CL…±â!Ö^Éa¯3öæbKe•‹±H™?ýÐpâ!(»f^}UܜŒc\ğÞÖN<Àņ#êíê¦ÄOƒ,FmŠüéMmµ0(°-÷á¤òMŒm¯Moh« "×Δô‘$¹»j? Øôf¶ÚÖ~SÚ»±ð=ާ7°Õö^zÑ哂|ú1¬4•|#Ùß³ÿåþcendstream +endobj +447 0 obj +935 +endobj +448 0 obj<>>>/Annots 47 0 R>>endobj +449 0 obj<>stream +xÚ­XKoÛ8¾çW zJJ©§èÁI“E€¦›u¼{ꅖh›…,i)ʎûëwHʎ,?¢C éÓÌ÷͋#ÿwEÀÃ/~¤¿ÓÕÕíôêæ!B`:Œ J|7ivMèçé¯+J¯ÿƒ¯²*) +Mª„Ñ+ @é’×z?½ò\íïLþD“‘ëAÇh”Rü“z.Éáå8Jö`ûh$jèE¾Bþ{ôHòJ‡ò c´:”ŸŸãøn`ïñó£× ÈϏÑêP~|ŽõñŠfžç·fR°YΡ¿ßçFb´8”›Ÿàvó0êʛ#£0 lׇ»ž_๬ÕK*E¥àAä\sz«[dË¢ž#¸†n2¾)w2^ñ"ã¨rœ•3ÞÅV²\H¶²Ï¸0]ÜÍY±h؂ƒ8ŽiEÆi‡ž‡\V@¼À Ûÿr«•yÄÍxvg<à +…®ÎíÚA«!=°zßA ~”àï‹øb4ÝÑE|ø$t½Ëøb>¡˜öKø.ñApÀÿö(Dr±‹{Ú£Ä~ߥnÂç\ò"åðĊ†å_0ÉBfpŸ %ÊB§ W¹hüÚÕ×ãá‘-L]OO÷ ¶‡y)átå‰l­zm­^³ªÊEÊ´¿›u‘¹iSÕN…ÏÕæ¹Ãʶ¾›C×zہõ:aµâr@cH ¼Ð-B¬t¸,N-™‚´,ÃJe £AÖd"Ւ˜Üš(‚CÚAÊì²¹5ñã,]Z‹mCdeÚ¬l:±æÖMmƒTIVԘÑÖ\Ïqƃ¹,WÆZ‡¶fô&&Ïµ¶vDï¢Õ·¬¹TÆVËÞ8ÀYϱ¢f~¢®Sn{W;ãn`Æ¢¨a#Ô£;/ ³­ÂٻœA–…ømj6¥Ìþï5¤ ý8€Ÿ×Ÿ&ìE}úùÙÄo&8řL—BñT5Ҏï^:¼×8}4CµõÂ&;#¹P*ç'íØ¸‘B3/çÝ@‘ç:3æFœ×ÜpîùÇ+\~1908Ët!ÔøW]•E-Ú¸a:´gQ,0*’cìuÒµA0&¬Sm¦Þ`KiœH çÏܞgMßtÁc¤ç ‹ö»˜I¬Ø½Ž¦0E\C…ÌRDf»ËÀUb>±{ó|ÛÏêC™çåFóкNeÏÔ.ƒšK<1„­[]ôÞû}ԊIµ/‰N—õ+|ßs°´q4¥Œ }¶¬VS©x¾Å𯎳©ní£5a;;Âčq|xVÝ­Ž­DzȚá·«œ$¡8¡ÌYÞ\ؽ P¢çz¿³6ŒÂ=–xá;`ЧÄMýäxÇØÍŐ¬Qæ9‘Y%ƒØ’Ò»ËYm S{ùG“;·•ÀÒÆÀŽ_î1QØê‹ËBÉHÏéaB-v¨P‹>!å‘ij5¡ñ±À2/å Œt5P ÁhÐgFvq¥‰CFäHߏ咇»¨7TžÁ–gÐgäá¹m_ÃFÔ¡aØøW£ªF} B_¿ò Th°ƒô…¤ÝLh¡ÂQWá8[3ÜÒ¾ œ„Ez(ÓÓG.Ýí9úU š†.Z´ íÓÃ%(Ái¯¾U‰§ó;Éðp²ØÁ1èÓµ{<>>>>>endobj +452 0 obj<>stream +xڍ˜Ks£8…÷ùZÎT5n$ñòb“¤=®N:“¸+kbËD=Ñ<ҏ_?Wº@ æ¡JUl£Ì9\]ùû%.üQ2²;^\n/Þo§’ēøPz©Pìœú¦ž?‡JQ ïÊãDÌ»í¯iëvÈáߜÛÈ¢Ûs0º4ºýF£Û~6n‡ ÜöOݾ®óTü<óú¾YEJ™%©pJ¹û»Ú«úùšQïGp²]­!k[kH×šï5Ú‡EüTûǧQª´®¤Êz|T…ü­²*†'›í ”]%wð¡èp"3^•N. +Gf»—Õ‚tskF:sáVg¥¥ÏÁtC£ô7º‘Îڐ‰ dÖëSñ7Ç8Ç{©êlo^ûE°Qu"+‘ˆ¢$‰|†T/‚¤âP½#ϪªÔñ)dòµK•Ê5’«Rj³J¢æ\=AàTüFxóSۘ+øš…”ò]û”BÖºrÜé”òÖMJq×u¸Û«›¬„ªx| ½És9- ёÇE\)MöÍ49í‰Rëل¬­'HOxâ‡èˆŽôV­O*w61~Lú§vl>³‡Øxh©&µg<¤äý5L•Y ‹ÎÁ‡†Fßhô¯ÃæžÝÈá´·ú}±žöÉùú¿U90@d >e5â烞³”¶óÒLßYLûùæú94m'÷»åmÑNdmíDzÂNÞ,oœ2°³—r·q)Wö¬4ªtbaˆ{`tFÉ£(ËL⼫ÅHGÖ6ґtNÛÚaIŒ÷Åfuœn®Ãc‘t4Dú‹šl£nÇ©i+غ[Ý£YÛ(Bz<ŠXÛBsaÄzad:Èûfýé¹q“åе•)¸Ñ®OäP@¸°‚‘»¡ÐIE–ÏYÛgŽôø3g‡â7B!/8=ú$ô¬ïÉ4ÇÉ3 +:)âcI [çi¢ñ{K óÃv>/Ë5¬µ\COÈõx3Ÿ9ÌgÞkWoeQ¨Â4ž“5n’íV÷p|F?ó¬—Xd­ëÚÐuM]T€ú^šÝ‰$®ä«˜Õ/3ݯN뿎Oë§ÐE–ú‘µÕô¸~M¹{q^/âîêãU·«íÔS=u™>¤÷غ²`“Íü\«©¤n7àX‚#Ä!tÁ„еžÈÚN¤Ç'õƒæÖ=7¯n_ +)`srm'EP¨JÿÐîH‡MÂÛ(ÙA;àìRµûï‡,Ǻ¯m]dH×¹ÞçÁÖçG6Ò/ô®{z½wiWb‹-²¶-Òã-ú«0T¿¨_ê +ˆM¼_ó3wq`tÌ:@ê|^¼Ù—ÛM/ƒÚÎ.OüòÒ>.²Õï¥Ë=<¶Gù»ßw>É}õbº¥Td ¼µÝ±…mr.ïwÃ.8-¶»a—›Ã)ãq#,€Ðz¡ñˆû*½ø¡c§Ž¦ØNþÖ±S©Þõ¯7³~pëø4¨õêÁÇÃóý&jŽrNB†¿ð<ü½ÙBÌ]}½„ð‡¹njóZ”2ÉôË®y›%Ž>ÑiÎôàÒæ¬‡¸Ô=æٛy¡ߏÉËþ½ø×Àþ[endstream +endobj +453 0 obj +1348 +endobj +454 0 obj<>>>>>endobj +455 0 obj<>stream +xÚŗMsâ8†ïüŠ>fªbdÉ_‡=LÈdf*Cm–°µEÕ\#@;`¼¶ÿߖÚ$ x÷’JʆæmÙïÓrKþ§ÇáÙÿ|Ù»õ>ÞIàFS9D‰ðM®D$=ÅF÷dŒ9UÙöq£M>·QÎB +3ø nWP¬ äó¬˜)0(¬AO¡V •5qÐ5¨ei¶6›Ç…Ø|ŽùýΉŸG=æ3tñr~™ø ¢HúÈ? +áK¨<¶hÓðE‹.ˆÆ^ԁHöԈÎ °Ä1ß¶^>-Ô)XÕÊdFzV”ÙLÕ°™ãÇɺ\¨_º˜µ`vH9Hpª# §í È©Oâ±Ãˆ'|‹'_—õ_zbö§“‹Àjê ‚^º#ÚÕ¿Ô¢¾`s<:ƒÃ:kÐiÉà9qcЩÉ૚ †iÔ<2q„ÓC‹_•žÍ͞G +ý?“aÊðrÝL’¶«IRŸ0GøX“ óD"MÔDg£m¹?Ûo+ý¬*¯.U®§:Ç YA`%¶éÄvÄ) ¾xó½üH)ÁùO¿€ü˜˜ížÿË`œ¶3§>&Œš[O°a&ñ!˜mêUõW‹UµÇ†_Cp ò=>¡æ‚7×e:zsÚÎޜú„7Qï ö¶”Ÿðö`gí¾7[gt1&Ø®']6洝9õ cœærŠ=)=êI7[£¬¯ïºPǶ§oú¼Ûô…';ðœuna¤íÌéÛyHZXŠ-,=janöþ^MTu´˜åóuñsÛt.øqÕŒïáåðãCË*ö”\Ú_Sú} 0áþþ8'Àœr‘Yµ—ãû¾M³'Ì´'LÆåŸF,#±{–¤mjç“–ŸbRâWuƒX¦äF2æI&Z?–Y~¼_ØÌµQm»/7-¤0úé ,,ôE–ÿ<ˆK»óŒ¢!FǃþA4"íýA8&ña8ÁðýñÐiΗçK$¹+)ÏՈÄT£³j*É©HoäT%ÁÙ®J«WiYVª®õªx¿…N0Ù¹g’¶k u{RF`Oò£¥`¸ÚôW뼕 ‘;'i»R!õ *QJSò¹„-\¼#–HtÞ.’¶3§>»]DX"Ƕ`y4ª|G,RtÞ,’¶3§nÁ‚.m^®GsƒoƒÏ`pÇ ÓUý?a˜ÕFU0Õ |³Ã—^²Ç{WYY.tžl>Ÿ‹‰oAz•ËÙqåÓw$åÖõ)²ÄeØH?Ü]mwöRûÉ$uų +º™ M”•.ðRÞD• +ðÂP¤Q˜yfœ _c2ki‰ßëµ6¾ÛJô>>>/Annots 156 0 R>>endobj +458 0 obj<>stream +xÚ͘ÛnÛF†ïýsé!Ã3E½p#Û0ª¥ôÊ@@“+› ÅUH*ŽòôYžF2µt€´( X ôíìîüÿì_Ïl°ðφÐ7€dsöûêìÝu¶oÎ`µÆß‚04X¥ç~\g¹€UÕZ”°(e-™¿Yý}vµ:³L ƒÑ?›þÝ݀c‡¦šlÀñlÓnŸrX6]y`ÛmGY=‰ÝÀýùõjqÿ² +RQ%eö RxØÃéþYØàšë„gò3×tô<#6à:S<'¬>;m>Žš”} +Unî®ßCäG†Váܤ﹨FÔp#œ­R6„Û¢e!j –uV<Då:Q³ Sêt³*Ո¯ežËgÂp*ÕE:iC;3LŽáÍ î <­¬`Ò|ׯ‘lÀp6ÍÃxÞ°YhºZš°oçò31N Éç«ã9A&ž>'ÈÄC¦N™˜çÒEBƏšr°.¾ë4~ w:~à_h\ñC\ÀU‘È”¾Ž‹´±ñV–õ¸}!Ú×°©„^é{†™ëü¡tþhéF~ ̀Þœ½?t<#zhxN ï»f¤ç|85N ?péÿ +Øí2Óú#˜öÇG™Š\™c)61IõëÍaùÈvæP:s´t£½†f™ÃžÀ9¼Qru<#ÈLô©å|H²iyF 9pÇЏŸùôÉäò‘…ª ü+ÌdÂ­™Â ˜‹*{,àFÆy…L‰¾™ØÍ~©¼ÈQ»¹²Ió ñQG+›èh n¸ÄêqNhZžä#¯ŸÉ)yl®Žâ¹JÇs‚|MÄçò.9BË3‚6Å«BË3‚6E"Ÿœ MqŠçòž;1׳pîy*Ÿœ@>ò¦xFlÀ›ôwà/ #ÞÀO×¥¹¬*gpי,â\¨’¤³ß².wI½+ȵúbXåû3cÇþ—õ‹+Þ¬¯_õ «ß–nÊSC3€öˆªMƒs‚ê1"wëxF JMÄgÕ£«¼ŽçÕ£ÕgêT=Z,—NHÇǁ…Bšÿà ¼ã|Œ·[RþAÔÏBða1Wf¹],z7œ8±¿¦¼ÿ´XâMd¢:º„ˆïµ(*ô)È­(•c‘ÔÅpiRVj.>Nw¦b¼A{ÎÅ:ÞåôY¡KU¼¥RŸo®VŸçWחŸ>¬à7°¾{–eß¿Ñ^¦1bÚFLYÄ~pP +, ¢™Æ–Joq]ãkW‹ª/Ÿj_ÕbÓÇêHü5Éãª2{S™*EùÃÝe%^×XÌ ¶µÕŽú|øÕHžâ²õá´Î•N§á´veœy\<îâGqÔÚl‡ÖÝoN¤å9ËshÇMi9î1Ûn ùe,¸FWGéºh2Vq1w·¬®î–šÎ+ÔÜvq~JÂçÕ·üRÈç‚L9«ôƒŎÔüßé×Oç_ͅË4íDë4»œÏ;Í:ÉÜ ÉbŒÒK¯~[Qí”b›ÇI»ˆT[‘dëLô Q~6ÓoŒJ8•ï1µÚA»2{Az£sбj#³é‚æ2Q™9žË)>+ÖòµìF–b¼ÁÈ,Sñ-KÄô$ª£_枟p_Ɋ¬Î°äö$´z)1Ô%v)·ÍA¦72ÍÖûê8q—°ÀjMoèÐ4Ëf)þ »Fÿ½ÛÖ°‰÷íVÔyp[£á2ݛp»ÆN¾Åy–¾lŒ‘±—£y©>³ + +I'¿e)α¦aóŁºqMËÍt~wy½ÔÑá¶Ï}{Ӝ‹F„¶ jj„Ž5ý’Ü =<å(ÐöÛcéŸgÿýnÛ¼endstream +endobj +459 0 obj +1470 +endobj +460 0 obj<>>>>>endobj +461 0 obj<>stream +xÚݗ_oÚ0Àßù÷H¥†&@<ì!…´jUm ²·JÈ$¸MìÔ1cìÓÏÆIIBZè†:m îÎ÷çwwá¹a)_tlõöãÆ•×¸¸€ÕiµÁ åovßR_ƒf·Õkua„#,0Œ9¡sxh¿§³‘{ïzîl<¹ýì¹ø揮ivÎμGi¯ –¥­AËVÖ¼%†@ÛJ2[,Á Â(p³ï8!…Òû$$8ÈåZ t6RîyE¸ü ÁÉ|%¤âXjîÕÑ͝˜á/O±(û×<‡²nQƒ"±â(2"D+´À{ªˆUõÌecÅIE¼¥®¥km[&Uº6*çbM¢H†'O¤U›$I ötÈq%E™0B¶¢Áž0ã¯É£•X2N~â Îá2F§­‹©Ð¸„,`¡4•Uȸ¸q½ÙðޙNÝiÅå(ҊŸY)¡R¡‰ÈsT(z(B2c¹âek +‚i‚6©Àq 6Y öéP½AB=;uõ?Ÿ*7…4laÈP+$-l,TJÞK_'ò÷šx+®kñÞŸÓ×§íÒÊ`y!§Z­špr£ó·‰9Ô°¹<¡!;V6f×+ÔDãx®ƒL_²Ú…˜a½Ä%‚ÈVÛ¨Bº´ëGy&KT¬(ÒÂ1 H¸)IU3ç¼ t²‘÷ê«Õ˜£ÀP!âT9&ËÙzGËõòíYêºlw–¯wÜæ¬ö^ýÞ,´Üº5O ЇíÌ>8¾wl¾›Âá;öfw_®^pèšÃÚÊ£²R˜ÄQÄÖ©¾+Wá<—“•Ÿo*ŒB·zo“R3 Þ=Çÿ.N!Oÿ-˜àGì—i™¸wî°LËà-\[©Ð’püS‘ñrKb¶£û7¡9íÓÕCsqÝÏ®­N쁙͛‰sí*õp« „òGŽõ”,¨úð9Iòmo(U£×6•¦e«[Ö` ™ôwÊõ_¿²bÿendstream +endobj +462 0 obj +771 +endobj +463 0 obj<>>>/Annots 185 0 R>>endobj +464 0 obj<>stream +xÚ­VËnâ0ÝówI¥Ip$¤Ò,ÊkÔªÕ0î* uê8é|ý\ãBI ‹Q¥7ç¾Î=×ö[Ë‚ø68D›V?luÆ.X„+üâõ\³á²=e/,’ð’.2øÍ㓹Hà*|AR´ùvk¤¯úŸ¥—ö·:T’Jc•æÉòœŠ&<Íås*ø_öÙÈÔë,Ç´uæ†c›žÊÜ5}Ó"0c†lEóX½3É*yšÀ¼=xœÌžf£ði8ß<އðÈ—›ùÕqå4ÐNÃgz\—é– ýKs”DôVðD2TJÁ¹d¬°Rõ)ûÈ$Ûì}•HüÅ4ËLÀh*Œ¯ë[¶Ó$þ@÷o9lYõIûÌÞá«=Si_êOÅkʍ˜&뜮ى)-;H,•Y•¹àu C¤í™®BθüoRk”N­Å‚. Å.fR#ÏÆzÏéú Ñ®š¨RM®–hîyÂ`R´~HÙ«ŸˆT¦Q+ÓQØ"&ÁiUK=¦?Àîºf\ÏCUnÀö{&)V1Ì>ϲëùñօ›·ï'Ãù +P‡ž©fD¨Ùâšó¨DހCT‰‡ý“’ÅzO}Áét<@¢ýàúb#®HáêT†ö^H€˜xG,Ëp¡§Ñë‘ãƍªÖrޞ=ô±Ù8¿8`1•ØâAºQÙÞªÔœÈ1ÑZïN¸Oގguè½f¯FmXÉt|×tZË&¦U¬JjqÙÅ%&K%3T’Ý~–r{ÝéÐ$73ºYP3ëNÄWÙW=š6<BÁß9u‰¡ I¶Bо0p¶Âº»jìÁ.éUÍÀف§ëRM8é ÇáéýúÌU‚«™ëáûJÝÌzæ¬óø +ñ]5 gñ⃋ø Šw]ûB>Uâ»ÖQ½ 3ª»U´a7£N—\î!Èw•ÿ){ç™:sl}î7«ªWtذlý»øô•ÿáôf‚êB¡‡hE#¦n|¨vu«Ž5å  ß&å%€âŽu§îXŵd:º §»ŸýYy- tz®¯Nµå"ùÕú%Œ$endstream +endobj +465 0 obj +864 +endobj +466 0 obj<>>>>>endobj +467 0 obj<>stream +xÚ-ŒÁ +‚@„ïûsԃ¶«’z萺B^*ý½ RÛ +i©‡¿6b>øæÅø7þÖT=XBl“GÔAø>BƒnVVîs‚ƒ´>U8Œ«ž»‹ÒÈôÒßG3jîŸk?6 Ì1¢ó7EdçEnˆÜЍQêA«Åt]ÐXæ¶-e!Sj‹cRaþ8ÛØ’Ø™}ý^- +endstream +endobj +468 0 obj +154 +endobj +469 0 obj<>>>>>endobj +470 0 obj<>stream +xÚ­•ÍnÂ0 Çï} +™´RÊÊ×uÀ&HLë $.„¥MI¤íé—ÓD–jmýKlÿm7k/„–½Bèµá© 4õžc/x@8€8±–n/‚˜5:ÐF\!5RqÔñÊr]CÇÙ¥~»ÛÜ¢ÁF«`㝠â%ÂÎÚÚ[”dÅá’Æc‘y5±®FÔHzЌsÚS Ê4µ°…š3„%*lêå &ø¼–`„RÌMU"Œk2X…av %rÂÒb]O £peå.Â躭$rZt|"BºÉ5+ ðçҗDaàö+ “k°·±á*) °ý$}ƒL¶_‡³wpÝÄ)0bH ·ãË%¢&Ô f+G…{uKÝ3Ö,Ê¿óDfF×*©ˆ¶î‹ú»½n‹&•¬ø)F£Iš „Ùlt›«si\ýµø"êNG—È6ÕEî‚9¡Ÿ˜±òÄ÷оÕê'Ð÷+§ø:\Ʌ"é5.d–T´ËŸ2àX¾Ø(;£2ÛÑt2Ÿ­Xÿϳ=Zý¨Õ<ŽF½¨Ù·g­µ‡÷a{oÞ/½endstream +endobj +471 0 obj +433 +endobj +472 0 obj<>>>>>endobj +473 0 obj<>stream +xڝ“ßOÂ0Çß÷WÜ#&î'£òªNßP¦¯f¶·­ÚÒv&ü÷¶l‚$JÖdÉõ{ßÏ]{Ý)$îKaLü¢ëà® â4…²ö!2Í£)”lT:¦21“ôª\:Y~…‰r/+[C[dÝ +58i·Fa+Ë¥€š¯Ð€FÃB‹£Þç ~7:ð\šE}é­¡^@àÂåÕEó;e±5×ð +{±ëSse/à­dcÎ÷Óï&Ã®6óæò~¦®•¨µÔ'…•`ÇbU5xB{éE)ÅÎuÅ 0®‘Z©·@¥› +. ÌçÅÀ«¥¬h JïÎøoP›5ÿ'+Œ‹¦ÇÁR¾÷u ØéàDÜãÈ&ñNÅóí¬„î_æ xÜÏAáªþ·7êÞ"LÇco²Ägf‰å qF»À&Ψªâýä=”ÁSð o|ìendstream +endobj +474 0 obj +338 +endobj +475 0 obj<>>>>>endobj +476 0 obj<>stream +xڝTÛn£0}ç+æqû-)Íå1‹’4RÕe•öÕ5êÆÖv6Êßï8´RoXÚs8sŽç˜ßIWtä0›Àõ¸J¾7ÉåzùšU¦³šöÛ6Ò8Çìé¢y7Ù|€¤7óle94h•0SÈó€ Þt2 åP*¾(-Õ,m}rU„sU——Õ8骪Ü!þÜ­‹0¯›ïZH„Æ2ív،7ÜÈÛm•nîÆùnñ(Ñû´b|„n,ëŸwp÷²)‡Oç¯ÔaÐŜ&üé/QÌ + +ÃU(LòðbÕ$?“¿ÇA8Qendstream +endobj +477 0 obj +425 +endobj +478 0 obj<>>>>>endobj +479 0 obj<>stream +xڝ’ÝRƒ0…ïyŠ½Ô °PŠxÙÛ)c”ø1M1 iýyzªíԙÆêÀ՞ÙosÎî‹BÏ|!ôûÓÆaï"O /m)Iã ¼8»F>ÏÏñ“Ñã½îGIw:{­™Ö>"tEԐâB3c)´’5̉¨Ö¤b[Â÷ÿaFÌþ1b&NÁO3œ‡O-J0 ™¨¸`̰+À¤]A.ur:Û=Ö2‘’ZRY»ˆåÍoD¢¹¤†R±0a´p£*"øG'8Øs49Ξç»X'„5NT1-²ã¬b]kÞ°'° ¡ ¼†ì>šm¹"u^2kþËY!—c$[]RşõÞ7k»‚;Dz§–Lm ©`mk;ª%]9X8ǎŠo¸YuÎkXÑ. ûðŒÒ¯¾$„Az$¶or7Ì1ø0¾GåvKB™µÇ+ñÓ¥öûà_F=ÛE¶‡i0€®0 "R%Å{ÓZ)ÃÞ­÷ š¶' endstream +endobj +480 0 obj +376 +endobj +481 0 obj<>>>/Annots 355 0 R>>endobj +482 0 obj<>stream +xÚ՜Ks7€ïúsÜÌ Þ3‡d‰rÙe¯µsK•‹¡F2‘Ô’”ÿûàÑ=Ffc\[\»Jª‡èFwãAþ÷„UµýÏ*Ã+¡«Åêäåìä狶bm5»­˜^i£ìÏÙÍ¿fóßï»js[mÖûn½ßý4ûãd:;©'µ¥¸Ìý¸zå•í¶ªÜÏð÷}uíøõí]õó…ªs¯èºµáÕXu‘«J¨I“óƒ(׋ÍCç@‘Rëre_ΪLŽþ;8B»‘æÊþ\UŠO4ˆ¡–0ÔÖޚk?Òb¬èÊödn´Ó—¹½¾±^±¼].æûåfýõQWfbŽiÜKcëß1Ž­o[7¢Œ[ ?¦¼4¦@nÌDçdéúËnß­ˆÉû[ Ö?4N‡ ÚûOÝöÓ²ûüuãH6iÂ8«¨¶±o +¬”UTÛNÀÓEÁ*Hfµ›ä€:ß,WÖÝóR„J9‘9€X0 ·õ̦adÀW†÷?ü=*à+#B¨ætÀG¼rÕñƒ(WÝm·í֋nw`ÛãŠ?_ù' +ÎoG ÷¡1.Ü+íß7/†{|…ƍì‚8pÎ~½¼&LûZçWµ3ZJ +ò@¹D¤ ­Ÿ×h%›HÓDhIêŽy1M ¹©mìÊÈ ÒûýÇnK˜#vwY¢v±(…`hÃsˆÅt@b­}›üßãw£cߜ($ÀÛÑP9ßK‘òÚÖÊÛõüþ0,¬ªViAœánç‡ãÛñE7U˜;µÝû³oŒŒgµ 1_”#¼†M¿uþ ÒÙÇùv¾ØS3)A¸‚Xº0–Û&â®;ª>Húº9é~g$TØÅòþÑ­sÄ,Z¶"&®Ð ‚¤lÃ,,†HäúÚ*ã‚ØsÞÎ×wó»Ž´¬îaŒ×ý#÷–ôOEÃÎÝöhæ`É$¦y+4H“Ø4Ñ£” +i$7nó #1’Þ½~7%âlìíjrí ²‚Y´QôqÆÃ–±µ­µŒÖ~Ýк”-cìhVÖ2T4LpnMb†plµ\u“ý—‡îx ]F%0­6Ð ‡QIÈý2î$¸PÝòr€ùa\l֟ £zæAԅ !똠Cƒ ’aZ–¥ dV×C4Èu¹Ùí¯Ûå¹Þ®S¤p̐¨€ÌírMfúayžw;ÿˆvC@ÌÊ&nŸS2((°bÖg?rö•æ7!{Ç÷ ržqH#²¬€Ìüï ò¦¼M;[”i†(«€¤é_ûn½³Fܼ„à\£µù0ç™þÉöÊbOë Œ?ဂ']^žF¥-ʺ¦ÉQ¨PN•ßÛ©Jñ†‰¤(ñ 2Þø2Ù{“*Å ·næddézñ±»y¼'—±ò%&‚€g›õíòîq;/‡„ãÜJÙّQQA îj¢UšB¨ë¤¦ñ 2HÔ kUÀfÒUzä[ÜÏw»nçòñíq¦ãÂ( +› ú’&4¨QMƒ%*–4Èv»Õ&‡ƒ`‹Ç‡Ý 1†ÒmcT øÓùôít6áR ÐúA͇xT<•É’Î.%6C3¡ ¼KÉïàR¬pˆï›û“¥Ð ‰µu_4ғ´ˆõvhž¤û¨dJ~¤ñ¶¯K>är|rëaþÄ6ƒ¡‚ãFIw6”›Ø äÓ´Vò¤fэ¢Q¡’®aÉ PˆÑÈ|?O*úlcµ¤ÿ¨:VÛMɃ€vÅ3x#ìt±èÊç&=N‰þÁ³s“ž÷fó;éD"yã¡üÍiJDÆ¢³³éåìÛ÷/¯KµvOöÕpFdkmD…Z;GDy?j¾o­]r%‘\Ë ҕ„‰µv[r%`»í:ÃA°«în±§7uÄI÷„ ‡ +À+¸RÒߥŸvøp¨`²BûjúfzVt¦„¶‚m錍 +¦Xe§]Áî.Øä(P0I•Ý~ÏM€QþÄá¹_„éP\ƚ›ÕÔÉNº:©u:Å£ð +UŠÝûü–Á@`#¶5#"܂ (ôÀQۚ³òÚŠ +2«å¯ÇmkFš[ñá ‚,Öòig‹2õð1QA&µü)õ¾éL•ú…±ä²hP(î! jo +(H6~…Ɔwý{ÒÛåš:‹½Ý¬iœÛ¥,¾ãŸ\¨|ÂC¼ã?ïVä ^™ñš'ïú<²Ó¶’´&^yhMáÆC eT[p €Úš±Î A®dwÛOäœe|8Æ]ðOAÌ»n·#?˜ô ‘.Ø³^ÞoÒ1.’Z607#¼@ý๒4p?¿Á¿)h$ÓTºŠ,[[¹:7媦§Ì¶ËOKêžgì¼òOg¤ MnÏS9¯ïŒ_`’@Ü?Vñ^¥¸Æ-,2œJqŨðƒo»¾ù#~Îތþ˜=Ü$W¥¯ý€Sm÷1m3øŒ}û¹ÒuÀB€¼ ªÔ1îW + B€œ/·¶2ßl—‡nÉ(v¬_?ÂZúž7 qÌßÝcTÜwWYý‚—ʺHñ™„gÄ gí÷®·_̃ö8nQÿ¸¿úóE~߸ONë&|ËÆÕéŬzQùÛ^ý•óÊֺ˻u•|šÐ!„r ä…áþ /ahÿsò73&Ï·endstream +endobj +483 0 obj +3110 +endobj +484 0 obj<>>>/Annots 360 0 R>>endobj +485 0 obj<>stream +xÚ͒Mnƒ0F÷>Å,›Æcƒeš”ª»6qPˆˆ‚i6½}ÇàôOBÙÐ ËöûÆOþ`‚^¥ýWuìÞ°¸, 0  V\‚ÎRªæíÎìö§úV½j;œæÈ \ÅôeóH,.@«œöu&¼ƒl}¿ îq™¢Ï¤6´*¦À%G˜Íø…í W߁!#L’©]7¶ûÃ!Zf<'´ˆßÔ#ñŠ^™R½è³z½T©'¥òšÒÀE!HÌp˜Ÿ@•ëíçœÔ$á궤N:ã2¿Ü3E§+ßâz³, D°z}ÞÂ]m×ìªÖõ¹=Xÿ«\û>´½õ„•‚(“ãáÚ6¸|a_þZ°aendstream +endobj +486 0 obj +273 +endobj +487 0 obj<>endobj +488 0 obj<>endobj +489 0 obj<>endobj +490 0 obj<>endobj +491 0 obj<>endobj +492 0 obj<>endobj +493 0 obj<>endobj +494 0 obj<>endobj +495 0 obj<>endobj +496 0 obj<>endobj +497 0 obj<>endobj +498 0 obj<>endobj +499 0 obj<>endobj +500 0 obj<>endobj +501 0 obj<>endobj +502 0 obj<>endobj +503 0 obj<>endobj +504 0 obj<>endobj +505 0 obj<>endobj +506 0 obj<>endobj +507 0 obj<>endobj +508 0 obj<>endobj +509 0 obj<>endobj +510 0 obj<>endobj +511 0 obj<>endobj +512 0 obj<>endobj +513 0 obj<>endobj +514 0 obj<>endobj +515 0 obj<>endobj +516 0 obj<>endobj +517 0 obj<>endobj +518 0 obj<>endobj +519 0 obj<>endobj +520 0 obj<>endobj +521 0 obj<>endobj +522 0 obj<>endobj +523 0 obj<>endobj +524 0 obj<>endobj +525 0 obj<>endobj +526 0 obj<>endobj +527 0 obj<>endobj +528 0 obj<>endobj +529 0 obj<>endobj +530 0 obj<>endobj +531 0 obj<>endobj +532 0 obj<>endobj +533 0 obj<>/Outlines 487 0 R/PageMode/UseOutlines/OpenAction[415 0 R/XYZ null null null]>>endobj +xref +0 534 +0000000000 65535 f +0000000015 00000 n +0000000225 00000 n +0000000286 00000 n +0000000360 00000 n +0000000438 00000 n +0000000515 00000 n +0000000594 00000 n +0000000670 00000 n +0000000751 00000 n +0000000809 00000 n +0000000924 00000 n +0000001009 00000 n +0000001124 00000 n +0000001209 00000 n +0000001324 00000 n +0000001409 00000 n +0000001524 00000 n +0000001609 00000 n +0000001724 00000 n +0000001807 00000 n +0000001922 00000 n +0000002006 00000 n +0000002121 00000 n +0000002206 00000 n +0000002321 00000 n +0000002406 00000 n +0000002521 00000 n +0000002606 00000 n +0000002721 00000 n +0000002806 00000 n +0000002921 00000 n +0000003006 00000 n +0000003100 00000 n +0000003201 00000 n +0000003286 00000 n +0000003387 00000 n +0000003472 00000 n +0000003573 00000 n +0000003658 00000 n +0000003759 00000 n +0000003844 00000 n +0000003945 00000 n +0000004030 00000 n +0000004131 00000 n +0000004216 00000 n +0000004317 00000 n +0000004402 00000 n +0000004468 00000 n +0000004533 00000 n +0000004618 00000 n +0000004683 00000 n +0000004768 00000 n +0000004833 00000 n +0000004918 00000 n +0000004983 00000 n +0000005068 00000 n +0000005133 00000 n +0000005218 00000 n +0000005284 00000 n +0000005369 00000 n +0000005435 00000 n +0000005520 00000 n +0000005586 00000 n +0000005671 00000 n +0000005737 00000 n +0000005822 00000 n +0000005888 00000 n +0000005973 00000 n +0000006039 00000 n +0000006124 00000 n +0000006190 00000 n +0000006275 00000 n +0000006341 00000 n +0000006426 00000 n +0000006492 00000 n +0000006577 00000 n +0000006643 00000 n +0000006728 00000 n +0000006794 00000 n +0000006879 00000 n +0000006945 00000 n +0000007030 00000 n +0000007096 00000 n +0000007181 00000 n +0000007247 00000 n +0000007332 00000 n +0000007398 00000 n +0000007483 00000 n +0000007549 00000 n +0000007634 00000 n +0000007700 00000 n +0000007785 00000 n +0000007851 00000 n +0000007936 00000 n +0000008002 00000 n +0000008087 00000 n +0000008153 00000 n +0000008238 00000 n +0000008304 00000 n +0000008389 00000 n +0000008456 00000 n +0000008543 00000 n +0000008610 00000 n +0000008697 00000 n +0000008764 00000 n +0000008851 00000 n +0000008918 00000 n +0000009005 00000 n +0000009072 00000 n +0000009159 00000 n +0000009226 00000 n +0000009313 00000 n +0000009380 00000 n +0000009467 00000 n +0000009534 00000 n +0000009621 00000 n +0000009688 00000 n +0000009775 00000 n +0000009842 00000 n +0000009929 00000 n +0000009996 00000 n +0000010083 00000 n +0000010150 00000 n +0000010237 00000 n +0000010304 00000 n +0000010391 00000 n +0000010458 00000 n +0000010545 00000 n +0000010612 00000 n +0000010699 00000 n +0000010766 00000 n +0000010853 00000 n +0000010920 00000 n +0000011007 00000 n +0000011074 00000 n +0000011161 00000 n +0000011228 00000 n +0000011315 00000 n +0000011382 00000 n +0000011469 00000 n +0000011536 00000 n +0000011623 00000 n +0000011690 00000 n +0000011777 00000 n +0000011844 00000 n +0000011931 00000 n +0000011998 00000 n +0000012085 00000 n +0000012152 00000 n +0000012239 00000 n +0000012306 00000 n +0000012393 00000 n +0000012460 00000 n +0000012547 00000 n +0000012614 00000 n +0000012701 00000 n +0000013125 00000 n +0000013192 00000 n +0000013279 00000 n +0000013346 00000 n +0000013433 00000 n +0000013500 00000 n +0000013587 00000 n +0000013654 00000 n +0000013741 00000 n +0000013808 00000 n +0000013895 00000 n +0000013962 00000 n +0000014049 00000 n +0000014106 00000 n +0000014192 00000 n +0000014259 00000 n +0000014346 00000 n +0000014413 00000 n +0000014500 00000 n +0000014567 00000 n +0000014654 00000 n +0000014721 00000 n +0000014808 00000 n +0000014875 00000 n +0000014962 00000 n +0000015029 00000 n +0000015116 00000 n +0000015183 00000 n +0000015270 00000 n +0000015400 00000 n +0000015504 00000 n +0000015609 00000 n +0000015715 00000 n +0000015821 00000 n +0000015927 00000 n +0000016033 00000 n +0000016139 00000 n +0000016245 00000 n +0000016351 00000 n +0000016457 00000 n +0000016561 00000 n +0000016666 00000 n +0000016772 00000 n +0000016878 00000 n +0000016984 00000 n +0000017090 00000 n +0000017196 00000 n +0000017302 00000 n +0000017406 00000 n +0000017511 00000 n +0000017617 00000 n +0000017723 00000 n +0000017829 00000 n +0000017935 00000 n +0000018041 00000 n +0000018147 00000 n +0000018253 00000 n +0000018359 00000 n +0000018465 00000 n +0000018571 00000 n +0000018677 00000 n +0000018783 00000 n +0000018889 00000 n +0000018995 00000 n +0000019101 00000 n +0000019207 00000 n +0000019313 00000 n +0000019419 00000 n +0000019525 00000 n +0000019631 00000 n +0000019737 00000 n +0000019843 00000 n +0000019949 00000 n +0000020055 00000 n +0000020161 00000 n +0000020267 00000 n +0000020373 00000 n +0000020479 00000 n +0000020585 00000 n +0000020691 00000 n +0000020797 00000 n +0000020903 00000 n +0000021009 00000 n +0000021115 00000 n +0000021221 00000 n +0000021327 00000 n +0000021431 00000 n +0000021536 00000 n +0000021642 00000 n +0000021748 00000 n +0000021854 00000 n +0000021960 00000 n +0000022066 00000 n +0000022172 00000 n +0000022278 00000 n +0000022384 00000 n +0000022490 00000 n +0000022596 00000 n +0000022702 00000 n +0000022808 00000 n +0000022914 00000 n +0000023020 00000 n +0000023126 00000 n +0000023232 00000 n +0000023338 00000 n +0000023444 00000 n +0000023550 00000 n +0000023656 00000 n +0000023762 00000 n +0000023868 00000 n +0000023974 00000 n +0000024080 00000 n +0000024186 00000 n +0000024292 00000 n +0000024398 00000 n +0000024504 00000 n +0000024610 00000 n +0000024716 00000 n +0000024822 00000 n +0000024928 00000 n +0000025034 00000 n +0000025140 00000 n +0000025246 00000 n +0000025352 00000 n +0000025458 00000 n +0000025564 00000 n +0000025670 00000 n +0000025776 00000 n +0000025882 00000 n +0000025988 00000 n +0000026094 00000 n +0000026200 00000 n +0000026306 00000 n +0000026412 00000 n +0000026518 00000 n +0000026624 00000 n +0000026730 00000 n +0000026836 00000 n +0000026942 00000 n +0000027048 00000 n +0000027154 00000 n +0000027260 00000 n +0000027366 00000 n +0000027472 00000 n +0000027578 00000 n +0000027684 00000 n +0000027790 00000 n +0000027896 00000 n +0000028002 00000 n +0000028108 00000 n +0000028214 00000 n +0000028320 00000 n +0000028426 00000 n +0000028532 00000 n +0000028638 00000 n +0000028744 00000 n +0000028850 00000 n +0000028956 00000 n +0000029062 00000 n +0000029168 00000 n +0000029274 00000 n +0000029380 00000 n +0000029486 00000 n +0000029592 00000 n +0000029698 00000 n +0000029804 00000 n +0000029910 00000 n +0000030016 00000 n +0000030122 00000 n +0000030228 00000 n +0000030334 00000 n +0000030440 00000 n +0000030546 00000 n +0000030652 00000 n +0000030758 00000 n +0000030864 00000 n +0000030970 00000 n +0000031076 00000 n +0000031182 00000 n +0000031288 00000 n +0000031394 00000 n +0000031500 00000 n +0000031606 00000 n +0000031712 00000 n +0000031818 00000 n +0000031924 00000 n +0000032030 00000 n +0000032136 00000 n +0000032242 00000 n +0000032348 00000 n +0000032454 00000 n +0000032560 00000 n +0000032666 00000 n +0000032769 00000 n +0000032872 00000 n +0000032975 00000 n +0000033079 00000 n +0000033181 00000 n +0000033284 00000 n +0000034654 00000 n +0000034758 00000 n +0000034863 00000 n +0000034967 00000 n +0000035072 00000 n +0000035122 00000 n +0000035156 00000 n +0000035190 00000 n +0000035785 00000 n +0000035834 00000 n +0000035883 00000 n +0000035932 00000 n +0000035981 00000 n +0000036030 00000 n +0000036079 00000 n +0000036128 00000 n +0000036177 00000 n +0000036226 00000 n +0000036275 00000 n +0000036324 00000 n +0000036373 00000 n +0000036422 00000 n +0000036471 00000 n +0000036520 00000 n +0000036569 00000 n +0000036618 00000 n +0000036667 00000 n +0000036716 00000 n +0000036765 00000 n +0000036814 00000 n +0000036863 00000 n +0000036912 00000 n +0000036961 00000 n +0000037010 00000 n +0000037059 00000 n +0000037108 00000 n +0000037157 00000 n +0000037206 00000 n +0000037255 00000 n +0000037304 00000 n +0000037353 00000 n +0000037402 00000 n +0000037451 00000 n +0000037500 00000 n +0000037549 00000 n +0000037598 00000 n +0000037647 00000 n +0000037696 00000 n +0000037745 00000 n +0000037794 00000 n +0000037843 00000 n +0000037892 00000 n +0000037941 00000 n +0000038218 00000 n +0000038370 00000 n +0000044766 00000 n +0000044788 00000 n +0000044901 00000 n +0000045003 00000 n +0000045023 00000 n +0000045163 00000 n +0000046071 00000 n +0000046092 00000 n +0000046205 00000 n +0000046396 00000 n +0000046417 00000 n +0000046557 00000 n +0000047157 00000 n +0000047178 00000 n +0000047291 00000 n +0000047485 00000 n +0000047506 00000 n +0000047646 00000 n +0000048434 00000 n +0000048455 00000 n +0000048609 00000 n +0000049916 00000 n +0000049938 00000 n +0000050087 00000 n +0000051074 00000 n +0000051095 00000 n +0000051244 00000 n +0000052056 00000 n +0000052077 00000 n +0000052208 00000 n +0000053302 00000 n +0000053324 00000 n +0000053464 00000 n +0000054230 00000 n +0000054251 00000 n +0000054409 00000 n +0000055415 00000 n +0000055436 00000 n +0000055599 00000 n +0000057077 00000 n +0000057099 00000 n +0000057221 00000 n +0000058640 00000 n +0000058662 00000 n +0000058802 00000 n +0000060010 00000 n +0000060032 00000 n +0000060196 00000 n +0000061737 00000 n +0000061759 00000 n +0000061899 00000 n +0000062741 00000 n +0000062762 00000 n +0000062917 00000 n +0000063852 00000 n +0000063873 00000 n +0000063986 00000 n +0000064211 00000 n +0000064232 00000 n +0000064381 00000 n +0000064885 00000 n +0000064906 00000 n +0000065046 00000 n +0000065455 00000 n +0000065476 00000 n +0000065616 00000 n +0000066112 00000 n +0000066133 00000 n +0000066264 00000 n +0000066711 00000 n +0000066732 00000 n +0000066887 00000 n +0000070068 00000 n +0000070090 00000 n +0000070236 00000 n +0000070580 00000 n +0000070601 00000 n +0000070656 00000 n +0000070761 00000 n +0000070905 00000 n +0000071011 00000 n +0000071131 00000 n +0000071240 00000 n +0000071389 00000 n +0000071499 00000 n +0000071606 00000 n +0000071764 00000 n +0000071875 00000 n +0000071994 00000 n +0000072145 00000 n +0000072249 00000 n +0000072353 00000 n +0000072530 00000 n +0000072639 00000 n +0000072796 00000 n +0000072902 00000 n +0000073019 00000 n +0000073126 00000 n +0000073285 00000 n +0000073395 00000 n +0000073522 00000 n +0000073647 00000 n +0000073768 00000 n +0000073887 00000 n +0000074014 00000 n +0000074182 00000 n +0000074329 00000 n +0000074479 00000 n +0000074627 00000 n +0000074781 00000 n +0000074929 00000 n +0000075073 00000 n +0000075223 00000 n +0000075371 00000 n +0000075519 00000 n +0000075667 00000 n +0000075800 00000 n +0000075934 00000 n +0000076057 00000 n +0000076175 00000 n +0000076309 00000 n +0000076406 00000 n +0000076506 00000 n +trailer +<> +startxref +76692 +%%EOF diff --git a/doc/idd.shtml b/doc/idd.shtml new file mode 100644 index 0000000000..4da9a9e298 --- /dev/null +++ b/doc/idd.shtml @@ -0,0 +1,1219 @@ + + + + + + DRAFT - CUPS Interface Design Description + + + +

Scope

+ +

Identification

+ +

This interface design description document provides detailed file +formats, message formats, and program conventions for the Common UNIX +Printing System ("CUPS") Version 1.0. + +

System Overview

+ +

The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +

This interface design description document is organized into the following +sections: + +

    +
  • 1 - Scope +
  • 2 - References +
  • 3 - Internal Interfaces +
  • 4 - External Interfaces +
  • 5 - Directories +
  • A - Glossary +
+ +

References

+ +

CUPS Documentation

+ +

The following CUPS documentation is referenced by this document: + +

    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan +
  • CUPS-IDD-1.0: CUPS System Interface Design Description +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual +
  • CUPS-SDD-1.0: CUPS Software Design Description +
  • CUPS-SPM-1.0: CUPS Software Programming Manual +
  • CUPS-SSR-1.0: CUPS Software Security Report +
  • CUPS-STP-1.0: CUPS Software Test Plan +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual +
  • CUPS-SVD-1.0.x: CUPS Software Version Description +
+ +

Other Documents

+ +

The following non-CUPS documents are referenced by this document: + +

    +
  • IEEE 1387.4, System Administration: Printing (draft) +
  • IPP/1.0: Additional Optional Operations - Set 1 +
  • IPP/1.0: Encoding and Transport +
  • IPP/1.0: Implementers Guide +
  • IPP/1.0: Model and Semantics +
  • RFC 1179, Line Printer Daemon Protocol +
+ +

Internal Interfaces

+ +

Character Set Files

+ +

The character set files define a mapping between 8-bit characters +and the Unicode character set. They are named using the ISO standard +number defined for the character set. Each file consists of up to 256 +lines of ASCII text. Each line consists of two hexadecimal numbers; the +first number is the character number in the character set (0x00 to +0xff), and the second number is the Unicode character number (0x0000 to +0xffff). + +

Language Files

+ +

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: + +

    +
  • us-ascii +
  • utf-8 +
  • iso-8859-1 +
  • iso-8859-2 +
  • iso-8859-3 +
  • iso-8859-4 +
  • iso-8859-5 +
  • iso-8859-6 +
  • iso-8859-7 +
  • iso-8859-8 +
  • iso-8859-9 +
  • iso-8859-14 +
  • iso-8859-15 +
+ +

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. + +

MIME Files

+ +

CUPS uses two MIME files in its standard configuration. + +

mime.types

+ +

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: + +

    +mime-type := super "/" type { SP rule }*
    +super := { "a-z" | "A-Z" }*
    +type := { "a-z" | "A-Z" | "-" | "." | "0-9" }*
    +rule := { extension | match | operator | "(" rule ")" }*
    +extension := { "a-z" | "A-Z" | "0-9" }*
    +match := "match(" regexp ")" |
    +         "ascii(" offset "," length ")" |
    +	 "printable(" offset "," length ")" |
    +	 "string(" offset "," string ")" |
    +	 "char(" offset "," value ")" |
    +	 "short(" offset "," value ")" |
    +	 "int(" offset "," value ")" |
    +	 "locale(" string ")"
    +operator := "+" |	[ logical AND ]
    +            "," | SP    [ logical OR ]
    +	    "!"         [ unary NOT ]
    +
+ +

The int and short rules match look for integers +in network byte order (a.k.a. big-endian) with the most-significant byte first. + +

mime.convs

+ +

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. + +

PostScript Printer Description Files

+ +

The PostScript Printer Description (PPD) file format is described in + +Adobe TechNote #5003: PostScript Printer Description File Format +Specification Version 4.3. + +

CUPS Extensions to PPD Files

+ +

CUPS adds several new attributes that are described below. + +

cupsFilter

+ +

This string attribute provides a conversion rule of the form: + +

    +source/type cost program
    +
+ +

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. + +

cupsManualCopies

+ +

This boolean attribute notifies the RIP filters that the destination printer +does not support copy generation in hardware. The default value is false. + +

cupsModelNumber

+ +

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. + +

cupsProfile

+ +

This string attribute specifies a color profile of the form: + +

    +resolution/type density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22
    +
+ +

The resolution and type values may be "-" to act as a +wildcard. Otherwise they must match one of the Resolution or +MediaType attributes defined in the PPD file. + +

The density and gamma values define gamma and density +adjustment function such that: + +

    +f(x) = density * xgamma
    +
+ +

The m00 through m22 values define a 3x3 transformation +matrix for the CMY color values. The density function is applied after +the CMY transformation. + +

cupsVersion

+ +

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". + +

Scheduler Configuration Files

+ +

The scheduler reads three configuration files that define the available +printers, classes, and services: + +

+ +
classes.conf +
This file defines all of the printer classes known to the + system. + +
cupsd.conf +
This file defines the files, directories, passwords, etc. + used by the scheduler. + +
printers.conf +
This file defines all of the printers known to the system. + +
+ +

classes.conf

+ +

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: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDescription
<Class name>
+ </Class>
<DefaultClass name>
+ </Class>
Info
Location
MoreInfo
Printer
+ +

cupsd.conf

+ +

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: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDefaultDescription
AccessLogSpecifies the location of the access log file (default + "logs/access_log").
Allow
AuthClass
AuthType
BrowseAddress
BrowseInterval
BrowsePort
BrowseTimeout
Browsing
DefaultCharset
DefaultLanguage
Deny
DocumentRoot
ErrorLog
Group
HostNameLookups
ImplicitClasses
KeepAlive
KeepAliveTimeout
<Location path>
+ </Location>
LogLevel
MaxClients
MaxLogSize
MaxRequestSize
Order
PageLog
Port
RIPCache
ServerAdmin
ServerName
ServerRoot
SystemGroup
TempDir
Timeout
User
+ +

printers.conf

+ +

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: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DirectiveDescription
<DefaultPrinter name>
+ </Printer>
DeviceURI
Info
Location
MoreInfo
<Printer name>
+ </Printer>
State
+ +

External Interfaces

+ +

AppSocket Protocol

+ +

The AppSocket protocol is an 8-bit clean TCP/IP socket connection. +The default IP service port is 9100. + +

CUPS Browsing Protocol

+ +

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 NL
    +
+ +

The state and uri values correspond to the IPP +printer-state and printer-uri-supported attributes. + +

The type value is a hexadecimal number string representing +capability/type bits: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitDescription
00 = printer
+ 1 = class
10 = local
+ 1 = remote
+ (always 1)
21 = can print B&W
31 = can print color
41 = can duplex
51 = can staple
61 = can do fast copies
71 = can do fast collating
81 = can punch holes
91 = can cover
101 = can bind
111 = can sort
121 = can print up to 9x14 inches
131 = can print up to 18x24 inches
141 = can print up to 36x48 inches
151 = can print variable sizes
+ +

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. + +

The MIME type for CUPS PostScript files is +application/vnd.cups-postscript. + +

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 Interface 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. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BytesDescriptionValues
0-63MediaClassNul-terminated ASCII string
64-127MediaColorNul-terminated ASCII string
128-191MediaTypeNul-terminated ASCII string
192-255OutputTypeNul-terminated ASCII string
256-259AdvanceDistance0 to 232 - 1 points
260-263AdvanceMedia0 = Never advance roll
+ 1 = Advance roll after file
+ 2 = Advance roll after job
+ 3 = Advance roll after set
+ 4 = Advance roll after page
264-267Collate0 = do not collate copies
+ 1 = collate copies
268-271CutMedia0 = Never cut media
+ 1 = Cut roll after file
+ 2 = Cut roll after job
+ 3 = Cut roll after set
+ 4 = Cut roll after page
272-275Duplex0 = Print single-sided
+ 1 = Print double-sided
276-283HWResolutionHorizontal and vertical resolution in dots-per-inch.
284-299ImagingBoundingBoxFour integers giving the left, bottom, right, and top positions + of the page bounding box in points
300-303InsertSheet0 = Do not insert separator sheets
+ 1 = Insert separator sheets
304-307Jog0 = Do no jog pages
+ 1 = Jog pages after file
+ 2 = Jog pages after job
+ 3 = Jog pages after set
308-311LeadingEdge0 = Top edge is first
+ 1 = Right edge is first
+ 2 = Bottom edge is first
+ 3 = Left edge is first
312-319MarginsLeft and bottom origin of image in points
320-323ManualFeed0 = Do not manually feed media
+ 1 = Manually feed media
324-327MediaPositionInput slot position from 0 to N
328-331MediaWeightMedia weight in grams per meter squared
332-335MirrorPrint0 = Do not mirror prints
+ 1 = Mirror prints
336-339NegativePrint0 = Do not invert prints
+ 1 = Invert prints
340-343NumCopies1 to 232 - 1
344-347Orientation0 = Do not rotate page
+ 1 = Rotate page counter-clockwise
+ 2 = Turn page upside down
+ 3 = Rotate page clockwise
348-351OutputFaceUp0 = Output face down
+ 1 = Output face up
352-359PageSizeWidth and length in points
360-363Separations0 = Print composite image
+ 1 = Print color separations
364-367TraySwitch0 = Do not change trays if selected tray is empty
+ 1 = Change trays if selected tray is empty
368-371Tumble0 = Do not rotate even pages when duplexing
+ 1 = Rotate even pages when duplexing
372-375cupsWidthWidth of page image in pixels
376-379cupsHeightHeight of page image in pixels
380-383cupsMediaTypeDriver-specific 0 to 232 - 1
384-387cupsBitsPerColor1, 2, 4, 8 bits
388-391cupsBitsPerPixel1 to 32 bits
392-395cupsBytesPerLine1 to 232 - 1 bytes
396-399cupsColorOrder0 = chunky pixels (CMYK CMYK CMYK)
+ 1 = banded pixels (CCC MMM YYY KKK)
+ 2 = planar pixels (CCC... MMM... YYY... KKK...)
400-403cupsColorSpace0 = white
+ 1 = RGB
+ 2 = RGBA
+ 3 = black
+ 4 = CMY
+ 5 = YMC
+ 6 = CMYK
+ 7 = YMCK
+ 8 = KCMY
+ 9 = KCMYcm
404-407cupsCompressionDriver-specific 0 to 232 - 1
408-411cupsRowCountDriver-specific 0 to 232 - 1
412-415cupsRowFeedDriver-specific 0 to 232 - 1
416-419cupsRowStepDriver-specific 0 to 232 - 1
+ +

The MIME type for CUPS Raster files is +application/vnd.cups-raster. + +

CUPS Raw Files

+ +

Raw files are printer-dependent print files that are in a format suitable +to the destination printer (e.g. HP-PCL, HP-RTL, etc.) The MIME type for CUPS +Raw files is application/vnd.cups-raw. + +

File Transfer Protocol

+ +

The File Transfer Protocol (FTP) is described by +RFC 959: File Transfer +Protocol. + +

Internet Printing Protocol

+ +

The Internet Printing Protocol is described by the following RFCs: + +

+ +

CUPS defines the following extension operations to IPP. + +

Get Default Destination (CUPS_GET_DEFAULT = 0x4001)

+ +

The get default destination operation returns the printer attributes +for the system default printer or class. The only required attributes +are attributes-charset and +attributes-natural-language. + +

Get default destination will only return ipp-ok. + +

Get Printers (CUPS_GET_PRINTERS = 0x4002)

+ +

The get printers operation returns the printer attributes for all +printers known to the system. The only required attributes are +attributes-charset and +attributes-natural-language. + +

Get printers will only return ipp-ok. + +

Add Printer (CUPS_ADD_PRINTER = 0x4003)

+ +

The add printer operation adds or replaces the specified printer. The +attributes-charset, +attributes-natural-language and printer-uri +attributes are required. + +

The printer-location, printer-info, +printer-more-info, and device-uri attributes +are required when initially adding a printer and optional when modifying +a printer. + +

A PPD file or System V interface script may follow the IPP request +body. If a valid interface script or PPD file is not provided then the +printer is treated as a generic PostScript device. + +

Add printer will return ipp-ok, ipp-not-authorized, +ipp-bad-request, or ipp-attributes. + +

Delete Printer (CUPS_DELETE_PRINTER = 0x4004)

+ +

The delete printer operation removes the specified printer. The only +required attributes are attributes-charset, +attributes-natural-language, and printer-uri. + +

Delete printer will return ipp-ok, ipp-not-found, +or ipp-not-authorized. + +

Get Classes (CUPS_GET_CLASSES = 0x4005)

+ +

The get classes operation returns the printer attributes for all +classes known to the system. The only required attributes are +attributes-charset and +attributes-natural-language. + +

Get classes will only return ipp-ok. + +

Add Class (CUPS_ADD_CLASS = 0x4006)

+ +

The add class operation adds or replaces the specified class. The +attributes-charset, +attributes-natural-language, and printer-uri +attributes are required. + +

The printer-location, printer-info, +printer-more-info, and member-uris attributes +are required when initially adding a printer and optional when modifying +a printer. + +

Add class will return ipp-ok, ipp-not-authorized, +ipp-bad-request, or ipp-attributes. + +

Delete Class (CUPS_DELETE_CLASS = 0x4007)

+ +

The delete class operation removes the specified class. The only +required attributes are attributes-charset, +attributes-natural-language, and printer-uri. + +

Delete class will return ipp-ok, ipp-not-found, +or ipp-not-authorized. + +

Accept Jobs (CUPS_ACCEPT_JOBS = 0x4008)

+ +

The accept jobs operation allows jobs to be accepted by the +specified destination. The only required attributes are +attributes-charset, +attributes-natural-language, and +printer-uri. + +

Accept jobs will return ipp-ok, ipp-not-found, +or ipp-not-authorized. + +

Reject Jobs (CUPS_REJECT_JOBS = 0x4009)

+ +

The reject jobs operation prevents jobs from being accepted by the +specified destination. The only required attributes are +attributes-charset, +attributes-natural-language, and +printer-uri. + +

Reject jobs will return ipp-ok, ipp-not-found, +or ipp-not-authorized. + +

Set Default Destination (CUPS_SET_DEFAULT = 0x400A)

+ +

The set default destination operation returns the printer attributes +for the system default printer or class. The only required attributes +are attributes-charset, +attributes-natural-language, and printer-uri. + +

Set default destination will return ipp-ok, +ipp-not-authorized, ipp-bad-request, or +ipp-not-found. + +

Line Printer Daemon Protocol

+ +

The Line Printer Daemon (LPD) protocol is described by +RFC 1179: Line Printer Daemon +Protocol. + +

Server Message Block Protocol

+ +

The Server Message Block (SMB) and related Common Internet File +System (CIFS) protocols are described at +http://anu.samba.org/cifs. + +

Trivial File Transfer Protocol

+ +

The Trivial File Transfer Protocol (TFTP) is described by +RFC 1350: The TFTP Protocol +(Revision 2). + +

5 - Directories

+ +
+ +
/usr/bin +
The cancel, lp, lpq, + lpr, lprm, and lpstat commands + reside here. + +
/usr/lib +
The accept, disable, enable, + lpadmin, and reject commands reside here. + +
/usr/sbin +
The lpc and cupsd commands resize here. + +
/usr/share/cups +
This is the root directory of the CUPS static data. + +
/usr/share/cups/data +
The character set and filter data files reside here. + +
/usr/share/cups/fonts +
The pstoraster font files reside here. + +
/usr/share/cups/model +
The sample PPD files reside here. + +
/usr/share/cups/pstoraster +
The pstoraster data files reside here. + +
/var/cups +
This is the root directory of the CUPS scheduler. + +
/var/cups/backend +
The backend filters reside here. + +
/var/cups/cgi-bin +
The CGI programs reside here. + +
/var/cups/conf +
The scheduler configuration and MIME files reside here. + +
/var/cups/doc +
The scheduler documentation files reside here. + +
/var/cups/filter +
The file filters reside here. + +
/var/cups/interfaces +
System V interface scripts reside here. + +
/var/cups/logs +
The access_log, error_log, and + page_log files reside here. + +
/var/cups/ppd +
This directory contains PPD files for each printer. + +
/var/cups/requests +
This directory contains pending print job files. + +
+ +

Glossary

+ +

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. + +
+ +

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 Printer 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 + +
PCL +
Page Control Language + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
+ + + diff --git a/doc/images/classes.gif b/doc/images/classes.gif new file mode 100644 index 0000000000..ace15df980 Binary files /dev/null and b/doc/images/classes.gif differ diff --git a/doc/images/cups-bar.gif b/doc/images/cups-bar.gif new file mode 100644 index 0000000000..b2bdf4b520 Binary files /dev/null and b/doc/images/cups-bar.gif differ diff --git a/doc/images/cups-block-diagram.gif b/doc/images/cups-block-diagram.gif new file mode 100644 index 0000000000..156a2e78ee Binary files /dev/null and b/doc/images/cups-block-diagram.gif differ diff --git a/doc/images/cups-large.gif b/doc/images/cups-large.gif new file mode 100644 index 0000000000..fc66ef07c0 Binary files /dev/null and b/doc/images/cups-large.gif differ diff --git a/doc/images/cups-medium.gif b/doc/images/cups-medium.gif new file mode 100644 index 0000000000..c45ed6ab9e Binary files /dev/null and b/doc/images/cups-medium.gif differ diff --git a/doc/images/cups-small.gif b/doc/images/cups-small.gif new file mode 100644 index 0000000000..6adb4a29ff Binary files /dev/null and b/doc/images/cups-small.gif differ diff --git a/doc/images/draft.gif b/doc/images/draft.gif new file mode 100644 index 0000000000..77d9716abd Binary files /dev/null and b/doc/images/draft.gif differ diff --git a/doc/images/logo.gif b/doc/images/logo.gif new file mode 100644 index 0000000000..9999795caa Binary files /dev/null and b/doc/images/logo.gif differ diff --git a/doc/images/navbar.gif b/doc/images/navbar.gif new file mode 100644 index 0000000000..3389d2338c Binary files /dev/null and b/doc/images/navbar.gif differ diff --git a/doc/images/navbar.xcf.gz b/doc/images/navbar.xcf.gz new file mode 100644 index 0000000000..28438a6bb8 Binary files /dev/null and b/doc/images/navbar.xcf.gz differ diff --git a/doc/images/printer-idle.gif b/doc/images/printer-idle.gif new file mode 100644 index 0000000000..68d990c628 Binary files /dev/null and b/doc/images/printer-idle.gif differ diff --git a/doc/images/printer-processing.gif b/doc/images/printer-processing.gif new file mode 100644 index 0000000000..a9a23f7951 Binary files /dev/null and b/doc/images/printer-processing.gif differ diff --git a/doc/images/printer-stopped.gif b/doc/images/printer-stopped.gif new file mode 100644 index 0000000000..76f45649b1 Binary files /dev/null and b/doc/images/printer-stopped.gif differ diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000000..99ff5b0b60 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,34 @@ + + + Common UNIX Printing System + + + Current Printer Status + Current Printer Classes Status + Current Jobs Status + Read CUPS Documentation On-Line + Download the Current CUPS Software + + + + +

+ +Easy Software Products Home Page + + +

Current Printer Status

+

Current Printer Classes Status

+

Current Jobs Status

+

Read CUPS Documentation On-Line

+

Download the Current CUPS Software

+ +
+ +

The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software +Products. CUPS is copyright 1997-1999 by Easy Software Products, +All Rights Reserved. + + + diff --git a/doc/overview.html b/doc/overview.html new file mode 100644 index 0000000000..a3979ab1cf --- /dev/null +++ b/doc/overview.html @@ -0,0 +1,287 @@ + + + + An Overview of the Common UNIX Printing System + + + + + + + + +

An Overview of the
+ Common UNIX Printing System

+ +

May 11, 1999
+ Michael Sweet, Easy Software Products
+ Copyright 1998-1999, All Rights Reserved.

+
+ +

This whitepaper describes the Common UNIX Printing +SystemTM ("CUPSTM"), a portable and extensible +printing system for UNIX®. CUPS is being developed by +Easy Software Products, a software firm located in Hollywood, Maryland +that has been selling commercial software for Silicon +Graphics®, Sun®, and HP workstations +since 1993 through more than 40 distributors serving over 80 countries +worldwide. + +

Additional information on CUPS is available on the World Wide Web at +"http://www.cups.org". + +

Background

+ +Printing within UNIX has historically been done using one of two +printing systems - the Berkeley Line Printer Daemon ("LPD") [RFC1179] +and the AT&T Line Printer system. Replacements for these printing +systems have emerged [LPRng, Palladin, PLP], however none of the +replacements change the fundamental capabilities of these systems. + +

Over the last few years several attempts at developing a standard +printing interface have been made, including the draft POSIX Printing +standard [IEEE-1387.4, last updated in 1994] and Internet Printing +Protocol [IETF-IPP]. The POSIX printing standard defines a common set +of command-line tools as well as a C interface for printer +administration and print jobs. The Internet Printing Protocol defines +extensions to the HyperText Transport Protocol 1.1 [RFC2068] to provide +support for remote printing services. + +

Weaknesses in Existing Printing Systems

+ +Easy Software Products has identified several major weaknesses in +the printing systems currently in use: + +
    + +
  1. Users must print text or Adobe® + PostScriptTM files; other formats may be + supported, but not universally. + +
  2. Lack of a standard command-line interface; each operating + system and driver package provides different command-line + options, e.g. setting the media size with one driver may + involve passing a single option ("letter") while another + requires two ("mediasize letter"). + +
  3. Lack of a standard application interface; most UNIX + applications either do not provide an interface for sending + printer options, or restrict the options to those in printer + description files supplied with the application. + +
  4. Remote printing problems; no vendor seems to use the same + remote printing protocol (many use an "enhanced" version of the + LPD protocol with vendor-specific extensions). + +
  5. Client printer administration hassles; most vendors + require that you install remote printers on each client by + hand, and many do not even provide the ability to browse + printers on the "server" system. + +
  6. Drivers typically are hardcoded to handle printing to + parallel or serial printers; support for other types of + interfaces or networking protocols requires that a driver be + rewritten to support them. + +
  7. Security, accounting, and quotas; most printing systems do + not support access control lists ("ACLs"), and printer + accounting and quotas are not well supported, if at all. + +
+ +

Goals of CUPS

+ +The basic goals of CUPS are: + +
    + +
  1. Provide standard support for text (US ASCII, UTF-8, and + ISO-8859-x), Adobe PostScript, PDF, HP-GL/2, TIFF, JPEG, PNG, + PBM, PGM, PPM, GIF, SGI RGB, Sun Raster, and Kodak + PhotoCDTM files. + +
  2. Provide a standard command-line interface with a standard + minimum set of options (media size and so forth). + +
  3. Provide a standard application interface. + +
  4. Provide a common remote printing interface (IPP). + +
  5. Provide a printer browsing interface and allow users to + print to remote printers using a "printer@server" notation + rather than adding the printer locally. + +
  6. Provide a scheduler extension interface to support + different interfaces separate from the printer driver (e.g. + serial, parallel, lpd, tftp, ipp, etc.) + +
  7. Provide a standard interface for ACLs, quotas, accounting, + and logging. + +
+ +

Design Overview

+ +Like most printing systems, CUPS is designed around a central print +scheduling process that dispatches print jobs, processes administrative +commands, provides printer status information to local and remote +programs, and informs users as needed. Figure 1 shows the basic +organization of CUPS. + +

+
Figure 1 - CUPS Block Diagram + +

Scheduler

+ +The scheduler is a HTTP/1.1 server application that handles HTTP +requests. Besides handling printer requests via IPP POST requests, the +scheduler also acts as a full-featured web server for documentation and +status monitoring. + +

The scheduler also monitors the LAN for printer browsing information +and dispatches print jobs as needed using the appropriate filters and +backends. + +

Configuration Files

+ +The configuration files consist of: + +
    + +
  • A HTTP server configuration file. + +
  • Printer and class definition files. + +
  • MIME type and conversion rule files. + +
  • PostScript Printer Description (PPD) files. + +
+ +The HTTP server configuration file is purposely similar to the +Apache server configuration file and defines all of the access control +properties for the server. + +

The printer and class definition files list the available printer +queues and classes. + +

The MIME type files list the supported MIME types (text/plain, +application/postscript, etc.) and "magic" rules for automatically +detecting the format of a file. These are used by the HTTP server to +determine the Content-Type field for GET and HEAD +requests, and by the IPP request handler to determine the file type +when a Print-Job request is received with a +document-format of application/octet-stream. + +

The MIME conversion rule files list the available filters. These +files are augmented by AddFilter entries in the printer +definition files. The filters are used when a job is dispatched so that +an application can send a convenient file format to the printing system +which then converts the document into a printable format as needed. + +

The PPD files describe the capabilities of PostScript printers. There is +one PPD file for each printer. + +

CUPS Interface Library

+ +The CUPS interface library contains CUPS-specific convenience functions +for queuing print jobs, etc. It also contains functions to access +resources via HTTP and IPP, perform MIME typing and conversion, and +manipulate PPD files. + +

Filters

+ +A filter program reads from the standard input or from a file if a +filename is supplied. All filters must support a common set of options +including printer name, job ID, username, job title, number of copies, +and job options. All output is sent to the standard output. + +

Backends

+ +A backend program is a special filter that writes incoming data to a +device or network connection. Backends for serial, parallel, LPD, TFTP, +FTP, IPP, SMB, and AppSocket (JetDirect) connections are provided in +CUPS 1.0. + +

Berkeley and System V Commands

+ +CUPS provides the System V and Berkeley command-line interfaces +for submitting jobs and checking the printer status. The "lpstat" and +"lpc status" commands also show network printers ("printer@hostname") +when printer browsing is enabled. + +

The System V administation commands are supplied for managing +printers local to the system. The Berkeley printer administration tool +("lpc") is only supported in a "read-only" mode to check the current +status of the printer queues and scheduler. + +

Summary

+ +The Common UNIX Printing System provides a modern printing interface +for UNIX applications that is both flexible and user-friendly. The +software provides System V and Berkeley compatible command-line +interfaces to ensure compatibility with existing applications. + +

Licensing

+ +CUPS is available under the terms of the Aladdin Free Public +License, which means that it is basically free except for commercial +distribution. Vendors wishing to license CUPS for their printing +solution should contact Easy Software Products at: + +
    +

    Attn: CUPS Licensing
    +Easy Software Products
    +44141 Airport View Drive Suite 204
    +Hollywood, Maryland 20636-3111 USA +

    +1.301.373.9600
    +cups-info@cups.org +

+ +

References

+ +
+ +
IEEE-1387.4
+ +
System Administration - Part 4: Printing Interfaces (draft)
+ +
IETF-IPP
+ +
Internet Printing Protocol/1.0
+ +
LPRng
+ +
An enhanced, extended, and portable implementation of the Berkeley LPR + print spooler functionality
+ +
Palladin
+ +
A printing system developed at the Massachussetts Institute of Technology
+ +
PLP
+ +
The Portable Line Printer spooler system
+ +
RFC1179
+ +
Line Printer Daemon Protocol
+ +
RFC2046
+ +
Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types
+ +
RFC2068
+ +
Hypertext Transfer Protocol -- HTTP/1.1
+ +
+ +

Trademarks

+ +The Common UNIX Printing System, CUPS, and the CUPS logo are +trademarks of Easy Software Products. All other trademarks are the +property of their respective owners. + + + diff --git a/doc/overview.pdf b/doc/overview.pdf new file mode 100644 index 0000000000..34e13ba325 Binary files /dev/null and b/doc/overview.pdf differ diff --git a/doc/sam.html b/doc/sam.html new file mode 100644 index 0000000000..3a0a0a6610 --- /dev/null +++ b/doc/sam.html @@ -0,0 +1,873 @@ + + +DRAFT - CUPS Software Administrators Manual + + + + + +

+

DRAFT - CUPS Software Administrators Manual


+CUPS-SAM-1.0.0
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
Preface + +1 - Printing System Overview + +2 - Building and Installing CUPS + +3 - Printer Queue Management + +4 - Printing System Management + +5 - Printer Accounting + +
+

Preface

+ This software administrators manual provides printer administration +information for the Common UNIX Printing System ("CUPS") Version 1.0.0. +

System Overview

+ The Common UNIX Printing System provides a portable printing layer for + UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

Document Overview

+

This software administrators manual is organized into the following +sections:

+
    +
  • 1 - Printing System Overview
  • +
  • 2 - Building and Installing CUPS
  • +
  • 3 - Printer Queue Management
  • +
  • 4 - Printing System Management
  • +
  • 5 - Printer Accounting
  • +
+

1 - Printing System Overview

+

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 MacOS, UNIX has no standard interface or system +in place for supporting printers. Among the solutions previously +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 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.

+

The Common UNIX Printing System, or 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, or IPP. IPP has been embraced by dozens of printer +and printer server manufacturers, and will be supported by the next +Microsoft Windows operating system.

+

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 secure printing solution than +older ones.

+

IPP is layered on top of the Hyper-Text Transport Protocol, or HTTP, +which is the basis of web servers on the Internet. This allows the user +to view documentation and status information on a printer or server +using their web browser.

+

CUPS provides a complete IPP/1.0-based printing system that provides +Basic authentication and domain or IP-based access control. Digest +authentication and TLS encryption will be available in future versions +of CUPS.

+

Jobs

+

Each file 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.

+

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. Backend filters perform the most +important task of all - they send the filtered print data to the +printer.

+

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 Processors, or RIPs, that convert +PostScript or image files into bitmaps that can be sent to a raster +printer.

+

CUPS provides backends for printing over parallel and serial ports, +and over the network via the JetDirect (AppSocket), Server Message +Block, and Line Printer Daemon protocols.

+

Printer Drivers

+

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes a sample printer driver for Hewlett-Packard +LaserJet and DeskJet printers. While this driver does not generate +optimal output for different printer models, it does 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. If there is only one occurrence of a +printer on a network, then that printer can be accessed using its name +alone. If more than one printer exists with the same name, users must +select the printer by specifying which server to use (e.g. +"printer@host1" or "printer@host2".)

+

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 goes down!

+

2 - Building and Installing CUPS

+

This chapter shows how to build and install the Common UNIX Printing +System. If you are installing a binary distribution from the CUPS web +site, proceed to the section titled, Installing a +Binary Distribution.

+

Installing a Source Distribution

+

Requirements

+

You'll need an ANSI C compiler to build CUPS on your system. As its +name implies, CUPS is designed to run on the UNIX operating system, +however the CUPS interface library and most of the filters and backends +supplied with CUPS should also run under Microsoft® Windows®.

+

For the image file filters and PostScript RIP, you'll need the JPEG, +PNG, TIFF, and ZLIB libraries. CUPS will build without these, but with +reduced functionality. Easy Software Products maintains a mirror of the +current versions of these libraries at:

+ +

If you make changes to the man pages you'll need GNU groff or +another nroff-like package. GNU groff is available from:

+ +

The documentation is formatted using the HTMLDOC software. If you +need to make changes you can get the HTMLDOC software from:

+ +

Compiling CUPS

+

CUPS uses GNU autoconf to configure the makefiles and source code +for your system. To configure CUPS for your system type:

+
    +
    +% ./configure ENTER
    +
    +
+

The default installation will put the CUPS software in the /usr + and /var directories on your system, which will overwrite +any existing printing commands on your system. To install the CUPS +software in another location use the --prefix option:

+
    +
    +% ./configure --prefix=/usr/local ENTER
    +
    +
+

If the PNG, JPEG, TIFF, and ZLIB libraries are not installed in a +system default location (typically /usr/include and +/usr/lib) you'll need to set the CFLAGS and +LDFLAGS environment variables prior to running configure:

+
    +
    +% setenv CFLAGS "-I/some/directory"
    +% setenv LDFLAGS "-L/some/directory"
    +% ./configure ... ENTER
    +
    +
+

Once you have configured things, just type:

+
    +
    +% make ENTER
    +
    +
+

to build the software.

+

Installing the Software

+

To install the software type:

+
    +
    +% make install ENTER
    +
    +
+

Running the Software

+ Once you have installed the software you can start the CUPS daemon by +typing: +
    +
    +% /usr/sbin/cupsd & ENTER
    +
    +
+

Installing a Binary Distribution

+

We are currently distributing CUPS binary distributions in TAR +format with installation and removal scripts.

+
    WARNING: +

    Installing CUPS will overwrite your existing printing system. If +you experience difficulties with the CUPS software and need to go back +to your old printing system, you will need to remove the CUPS software +with the provided script and reinstall the printing system from your +operating system CDs.

    +
+

To install the CUPS software you will need to be logged in as root +(doing an "su" is good enough). Once you are the root user, run the +installation script with:

+
    +
    +./cups.install ENTER
    +
    +
+

After asking you a few yes/no questions the CUPS software will be +installed and the scheduler will be started automatically.

+

3 - Printer Queue Management

+

This chapter discusses how to add, modify, and delete print queues +on your system.

+

The lpadmin Command

+

The lpadmin command allows you to perform most printer +administration tasks from the command-line. Since lpadmin + is also a System V printing system command, it is located in the +/usr/lib directory instead of a more common one like +/usr/bin or /usr/sbin.

+

Adding and Modifying Printers

+

To add a printer to CUPS you simply run the lpadmin + command with the "-p" option:

+
    +
    +% /usr/lib/lpadmin -pprinter -E -vdevice -Pppd ENTER
    +
    +
+

Spaces between the option letter and value are optional.

+

The printer name can be up to 127 letters, digits, hyphens, +and underscores. Unlike other printing systems, the printer name in +CUPS is not case-sensitive, so you can't add two printers named +LaserJet and laserjet.

+

The device argument specifies the device URI or filename for +the printer. The following devices are supported in a basic +installation of CUPS:

+
+
file:/dev/filename
+
/dev/filename
+
Sends all output to the specified file.
+
http://[username:password@]hostname[:port]/resource
+
ipp://[username:password@]hostname[:port]/resource
+
Sends all output to the specified IPP printer or server. The +port parameters defaults to 631.
+
lpd://hostname/queue
+
Sends all output to the specified LPD printer queue.
+
parallel:/dev/filename
+
Sends all output to the specified parallel port device.
+
serial:/dev/filename[?options]
+
Sends all output to the specified serial port device. The +options can be any of the following separated by the plus (+) +character: +
    +
  • baud=rate - Sets the baud rate for the device.
  • +
  • bits=7 or 8 - Sets the number of data bits.
  • +
  • parity=even - Sets even parity checking.
  • +
  • parity=odd - Sets odd parity checking.
  • +
  • parity=none - Turns parity checking off.
  • +
+
+
smb://[username:password@]hostname/queue
+
Sends all output to the specified SMB (Windows) printer queue + using the SAMBA software.
+
socket://hostname[:port]
+
Sends all output to the specified printer using the AppSocket +protocol. The port parameter defaults to 9100.
+
+

The ppd argument specifies the PostScript Printer Description +file to use for this printer. Many options (such as media size, etc.) +will not be available if you omit this part of the lpadmin + command.

+

Using Standard Printer Drivers

+

The lpadmin command allows you to use "standard" PPD +files and interface scripts located in the /usr/share/cups/model + directory with the "-m" option:

+
    +
    +% /usr/lib/lpadmin -pprinter -E -vdevice -mmodel ENTER
    +
    +
+

The model argument specifies the name of the PPD file or +interface script. For example, to add a printer using the sample HP +DeskJet series driver connected to parallel port 1 under Linux you +would use:

+
    +
    +% /usr/lib/lpadmin -pDeskJet -E -vparallel:/dev/par1 -mdeskjet.ppd ENTER
    +
    +
+

Removing Printers

+

To remove a printer to CUPS you simply run the lpadmin + command with the "-x" option:

+
    +
    +% /usr/lib/lpadmin -xprinter ENTER
    +
    +
+

Printer Classes

+

CUPS allows you to group similar printers in a printer class. +When a user sends a print job to a class, the job will be processed by +the first available printer in that class.

+

To add a printer to a class you simply run the lpadmin + command with the "-p" and "-c" options:

+
    +
    +% /usr/lib/lpadmin -pprinter -cclass ENTER
    +
    +
+

The class is created automatically if it doesn't exist. To +remove a class just use the "-x" option:

+
    +
    +% /usr/lib/lpadmin -xclass ENTER
    +
    +
+

Setting the Default Printer

+

To set the default printer or class simply run the lpadmin + command with the "-d" option:

+
    +
    +% /usr/lib/lpadmin -ddestination ENTER
    +
    +
+

The destination argument is the name of the printer or class.

+

Starting and Stopping Printers

+

The enable and disable commands start and +stop printer queues, respectively:

+
    +
    +% /usr/bin/enable printer ENTER
    +% /usr/bin/disable printer ENTER
    +
    +
+

Printers that are disabled may still accept jobs for printing, but +won't actually print any files until they are restarted. This is useful +if the printer malfunctions and you need time to correct the problem. +Any queues jobs are printed after the printer is enabled (started).

+

Accepting and Rejecting Print Jobs

+

The accept and reject commands accept and +reject print jobs for the named printer, respectively:

+
    +
    +% /usr/lib/accept printer ENTER
    +% /usr/lib/reject printer ENTER
    +
    +
+

As noted above, a printer can be stopped but accepting new print +jobs. A printer can also be rejecting new print jobs while it finishes +those that have been queued. This is useful for when you must perform +maintenance on the printer and will not have it available to users for +a long period of time.

+

4 - Printing System Management

+

This chapter shows how you can configure the CUPS server.

+

Changing the Configuration Files

+

All of the server configuration files are located in the +/var/cups/conf directory. Once you have made a change to a file +you need to restart the CUPS server by sending it a HUP signal or using +the supplied script "cups.sh":

+
    +
    +% ./cups.sh restart ENTER
    +
    +
+

The binary distribution installs the script in the init.d + directory with the name lp or lpd depending +on the vendor-supplied printing system.

+

Temporary Files

+

Normally CUPS puts all of its temporary files in /var/tmp +. If you'd like to change this directory you'll need to edit the +/var/cups/conf/cupsd.conf file.

+

Start by creating the new temporary directory and setting the +appropriate permissions:

+
    +
    +% mkdir /foo/bar/tmp ENTER
    +% chmod a+rwxt /foo/bar/tmp ENTER
    +
    +
+

Then change the line containing the TempDir directive +in the cupsd.conf to the directory that you've created:

+
    +
    +TempDir /foo/bar/tmp
    +
    +
+

Finally, restart the server as outlined in the first section of this +chapter.

+

Network Configuration

+

The default configuration of the CUPS server listens for connections +from all network interfaces on port 631 (the standard IPP port). +Administration functions are limited to local connections with the +appropriate username and password.

+

If you'd like to limit access to your system you'll need to edit the +/var/cups/conf/cupsd.conf file.

+

Port

+

The Port directive specifies a port to listen on for +all interfaces. Besides the standard IPP port (631) you can also setup +your server to listen on the HTTP port (80) to use your CUPS server as +a standard web server as well.

+

Listen

+

The Listen directive specifies a listening address and +port, extending the functionality of the Port directive. +If you want to allow connections only from the local machine you can +use:

+
    +
    +Listen 127.0.0.1:631
    +
    +
+

instead of the Port directive.

+

If you want to limit access to a specific network/subnet, make sure +you specify only the network address and not your system's network +address!

+

BrowsePort

+

The BrowsePort directive controls which port is +monitored for remote printers. By default it is set to the IPP port +(631), however you can change it as needed.

+
    NOTE: +

    You must set the BrowsePort to the same value on all +of the systems that you want to see.

    +
+

BrowseAddress

+

The BrowseAddress directive specifies a broadcast +address to use when sending printer status updates over the network. +The default browse address is 255.255.255.255 which will +send printer information to all subnets.

+
    NOTE: +

    If you are using HP-UX 10.20 and a subnet that is not 24, 16, or 8 +bits, printer browsing (and in fact all broadcast reception) will not +work. This problem appears to be fixed in HP-UX 11.0.

    +
+

Printer Security

+

CUPS provides IP and domain-name based access control and Basic +authentication for authentication.

+

Location

+

The Location directive defines access control for a +specific HTTP directory. The following pseudo directories are provided +by the CUPS server:

+
    +
  • /admin - This is the URI that must be referenced to + do printer administation commands.
  • +
  • /classes - This is the URI that must be referenced to + access printer classes.
  • +
  • /jobs - This is the URI that must be referenced to + access jobs.
  • +
  • /printers - This is the URI that must be referenced to + access printers.
  • +
+

All other directories are taken from the /usr/share/cups/doc + directory.

+

The Location directive surrounds the other access +control directives described below. The default server configuration +uses:

+
    +
    +<Location /admin>
    +AuthType Basic
    +AuthClass System
    +
    +Order Deny,Allow
    +Deny From All
    +Allow From 127.0.0.1
    +</Location>
    +
    +
+

Order

+

The Order directive defines the default access control. +The following values are supported:

+
    +
  • Order Allow,Deny - Allow requests from all systems +except for those listed in a Deny directive.
  • +
  • Order Deny,Allow - Allow requests only from those +listed in an Allow directive.
  • +
+

The Order directive must appear inside a Location + directive.

+

Allow

+

The Allow directive specifies a hostname, IP address, +or network that is allowed access to the server:

+
    +
    +Allow from All
    +Allow from None
    +Allow from *.domain.com
    +Allow from .domain.com
    +Allow from host.domain.com
    +Allow from nnn.*
    +Allow from nnn.nnn.*
    +Allow from nnn.nnn.nnn.*
    +Allow from nnn.nnn.nnn.nnn
    +Allow from nnn.nnn.nnn.nnn/mm
    +Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
    +
+

Allow directives are cummulative, so multiple +Allow directives can be used to allow access for multiple hosts +or networks. The /mm notation specifies a CIDR netmask: +

+ + + + + + + + + + +
mmnetmask
00.0.0.0
1128.0.0.0
2192.0.0.0
......
8255.0.0.0
16255.255.0.0
24255.255.255.0
32255.255.255.255
+
+

+

The Allow directive must appear inside a Location + directive.

+

Deny

+

The Deny directive specifies a hostname, IP address, or +network that is allowed access to the server:

+
    +
    +Deny from All
    +Deny from None
    +Deny from *.domain.com
    +Deny from .domain.com
    +Deny from host.domain.com
    +Deny from nnn.*
    +Deny from nnn.nnn.*
    +Deny from nnn.nnn.nnn.*
    +Deny from nnn.nnn.nnn.nnn
    +Deny from nnn.nnn.nnn.nnn/mm
    +Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
    +
+

Deny directives are cummulative, so multiple Deny + directives can be used to allow access for multiple hosts or networks. + The /mm notation specifies a CIDR netmask: +

+ + + + + + + + + + +
mmnetmask
00.0.0.0
1128.0.0.0
2192.0.0.0
......
8255.0.0.0
16255.255.0.0
24255.255.255.0
32255.255.255.255
+
+

+

The Deny directive must appear inside a Location + directive.

+

AuthType

+

The AuthType directive defines the type of +authentication to perform:

+
    +
  • None - No authentication should be performed + (default.)
  • +
  • Basic - Basic authentication should be performed +using the UNIX password and group files.
  • +
+

The AuthType directive must appear inside a +Location directive.

+

AuthClass

+

The AuthClass directive defines what level of +Basic access is required:

+
    +
  • Anonymous - No authentication should be performed + (default.)
  • +
  • User - A valid username and password is required.
  • +
  • System - A valid username and password is required, +and the username must belong to the "sys" group (this can be changed +using the SystemGroup directive, below.
  • +
  • Group - A valid username and password is required, +and the username must belong to the group named by the +AuthGroupName directive.
  • +
+

The AuthClass directive must appear inside a +Location directive.

+

AuthGroupName

+

The AuthGroupName directive sets the group to use for +Group authentication.

+

The AuthGroupName directive must appear inside a +Location directive.

+

SystemGroup

+

The SystemGroup directive sets the administration group +used when authenticating the System type. It defaults to +the "sys" group.

+

File Formats

+

CUPS provides a MIME-based file typing and filtering mechanism to +convert files to a printable format for each printer. The +mime.types and mime.convs files define the file +type and filters that are available on the system.

+

mime.types

+

The mime.types defines the known file types. Each line +of the file starts with the MIME type and may be followed by one or +more file type recognition rules. For example, the text/html + file type is defined as:

+
    +
    +text/html html htm \
    +          printable(0,1024) + (string(0,"<HTML>") string(0,"<!DOCTYPE"))
    +
    +
+

The first two rules say that any file with an extension of ".html" +or ".htm" is a HTML file. The third rules says that any file whose +first 1024 characters are printable text and starts with the strings +"<HTML>" or "<!DOCTYPE" is a HTML file as well.

+

The first two rules deal solely with the name of the file being +typed. This is useful when the original filename is known, however for +print files the server doesn't always have a filename to work with. The +third rule takes care of this possibility and automatically figures out +the file type based upon the contents of the file instead.

+

The available tests are:

+
    +
  • ( expr ) - Parenthesis for expression grouping
  • +
  • + - Logical AND
  • +
  • , or whitespace - Logical OR
  • +
  • ! - Logical NOT
  • +
  • match("pattern") - Pattern match on filename
  • +
  • extension - Pattern match on "*.extension"
  • +
  • ascii(offset,length) - True if bytes are valid + printable ASCII (CR, NL, TAB, BS, 32-126)
  • +
  • printable(offset,length) - True if bytes are + printable 8-bit chars (CR, NL, TAB, BS, 32-126, 160-254)
  • +
  • string(offset,"string") - True if bytes are identical +to string
  • +
  • char(offset,value) - True if byte is identical
  • +
  • short(offset,value) - True if 16-bit integer is +identical (network or "big-endian" byte order)
  • +
  • int(offset,value) - True if 32-bit integer is + identical (network or "big-endian" byte order)
  • +
  • locale("string") - True if current locale matches +string
  • +
+

mime.convs

+

The mime.convs file defines all of the filter programs +that are known to the system. Each line consists of:

+
    +
    +source destination cost program
    +
    +text/plain application/postscript 50 texttops
    +application/vnd.cups-postscript application/vnd.cups-raster 50 pstoraster
    +image/* application/vnd.cups-postscript 50 imagetops
    +image/* application/vnd.cups-raster 50 imagetoraster
    +
    +
+

The source field is a MIME type, optionally using a wildcard +for the super-type or sub-type (e.g. "text/plain", "image/*", +"*/postscript").

+

The destination field is a MIME type defined in the +mime.types file.

+

The cost field defines a relative cost for the filtering +operation from 1 to 100. The cost is used to choose between two +different sets of filters when converting a file. For example, to +convert from image/jpeg to +application/vnd.cups-raster, you could use the imagetops + and pstoraster filters for a total cost of 100, or the +imagetoraster filter for a total cost of 50.

+

The program field defines the filter program to run; the +special program "-" can be used to make two file types equivalent. The +program must accept the standard filter arguments and environment +variables described in the CUPS Interface Design Document:

+
    +
    +program job user title options [filename]
    +
    +
+

If specified, the filename argument defines a file to read +when filtering, otherwise the filter must read from the standard input. +All filtered output must go to the standard output.

+

5 - Printer Accounting

+ This chapter describes the CUPS log files. +

Where to Find the Log Files

+

The log files are normally stored in the /var/cups/logs + directory. You can change this by editing the +/var/cups/conf/cupsd.conf configuration file.

+

The access_log File

+

The access_log file lists each HTTP resource that is +accessed by a web browser or CUPS/IPP client. Each line is in the +so-called "Common Log Format" used by many web servers and web +reporting tools:

+
    +
    +host group user date-time \"method resource version\" status bytes
    +
    +127.0.0.1 - - [20/May/1999:19:20:29 +0000] "POST /admin/ HTTP/1.1" 401 0
    +127.0.0.1 - mike [20/May/1999:19:20:31 +0000] "POST /admin/ HTTP/1.1" 200 0
    +
    +
+

The host field will normally only be an IP address unless you +have changed the HostnameLookups directive on in the +cupsd.conf file.

+

The group field always contains "-".

+

The user field is the authenticated username of the +requesting user. If no username and password is supplied for the +request then this field contains "-".

+

The date-time field is the date and time of the request in +Greenwich Mean Time (a.k.a. ZULU) and is in the format:

+
    +
    +[DD/MON/YYYY:HH:MM:SS +0000]
    +
    +
+

The method field is the HTTP method used ("GET", "PUT", +"POST", etc.)

+

The resource field is the filename of the requested resource.

+

The version field is the HTTP specification version used by +the client. For CUPS clients this will always be "HTTP/1.1".

+

The status field contains the HTTP result status of the +request. Usually it is "200", but other HTTP status codes are possible. +For example, 401 is the "unauthorized access" status in the example +above.

+

The bytes field contains the number of bytes in the request. +For POST requests the bytes field contains the number of bytes +of non-IPP data that is received from the client.

+

The error_log File

+

The error_log file lists messages from the scheduler +(errors, warnings, etc.):

+
    +
    +level date-time message
    +
    +I [20/May/1999:19:18:28 +0000] Job 1 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:21:02 +0000] Job 2 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:22:24 +0000] Job 2 was cancelled by 'mike'.
    +
    +
+

The level field contains the type of message:

+
    +
  • E - An error occurred.
  • +
  • W - The server was unable to perform some action.
  • +
  • I - Informational message.
  • +
  • D - Debugging message.
  • +
+

The date-time field contains the date and time of when the +page started printing. The format of this field is identical to the +data-time field in the access_log file.

+

The message fields contains a free-form textual message.

+

The page_log File

+

The page_log file lists each page that is sent to a +printer. Each line contains the following information:

+
    +
    +printer user job-id date-time page-number num-copies
    +
    +DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 0
    +
    +
+

The printer field contains the name of the printer that +printed the page. If you send a job to a printer class, this field will +contain the name of the printer that was assigned the job.

+

The user field contains the name of the user (the IPP +requesting-user-name attribute) that submitted this file for +printing.

+

The job-id field contains the job number of the page being +printed. Job numbers are reset to 1 whenever the CUPS server is +started, so don't depend on this number being unique!

+

The date-time field contains the date and time of when the +page started printing. The format of this field is identical to the +data-time field in the access_log file.

+

The page-number and num-pages fields contain the page +number and number of copies being printed of that page. For printer +that can not produce copies on their own, the num-pages field +will always be 1.

+ + diff --git a/doc/sam.pdf b/doc/sam.pdf new file mode 100644 index 0000000000..244562c0d4 --- /dev/null +++ b/doc/sam.pdf @@ -0,0 +1,1114 @@ +%PDF-1.2 +%âãÏÓ +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +4 0 obj<>endobj +5 0 obj<>endobj +6 0 obj<>endobj +7 0 obj<>endobj +8 0 obj<>endobj +9 0 obj<>endobj +10 0 obj<>endobj +11 0 obj<>endobj +12 0 obj<>endobj +13 0 obj<>endobj +14 0 obj<>endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj[11 0 R +12 0 R +13 0 R +14 0 R +16 0 R +]endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj<>endobj +22 0 obj[19 0 R +21 0 R +]endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj<>endobj +26 0 obj<>endobj +27 0 obj<>endobj +28 0 obj<>endobj +29 0 obj<>endobj +30 0 obj<>endobj +31 0 obj<>endobj +32 0 obj<>endobj +33 0 obj<>endobj +34 0 obj<>endobj +35 0 obj<>endobj +36 0 obj<>endobj +37 0 obj<>endobj +38 0 obj<>endobj +39 0 obj<>endobj +40 0 obj<>endobj +41 0 obj<>endobj +42 0 obj<>endobj +43 0 obj<>endobj +44 0 obj<>endobj +45 0 obj<>endobj +46 0 obj<>endobj +47 0 obj<>endobj +48 0 obj<>endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj<>endobj +52 0 obj<>endobj +53 0 obj<>endobj +54 0 obj<>endobj +55 0 obj<>endobj +56 0 obj<>endobj +57 0 obj<>endobj +58 0 obj<>endobj +59 0 obj<>endobj +60 0 obj<>endobj +61 0 obj<>endobj +62 0 obj<>endobj +63 0 obj<>endobj +64 0 obj<>endobj +65 0 obj<>endobj +66 0 obj<>endobj +67 0 obj<>endobj +68 0 obj<>endobj +69 0 obj<>endobj +70 0 obj<>endobj +71 0 obj<>endobj +72 0 obj<>endobj +73 0 obj<>endobj +74 0 obj<>endobj +75 0 obj<>endobj +76 0 obj<>endobj +77 0 obj<>endobj +78 0 obj<>endobj +79 0 obj<>endobj +80 0 obj<>endobj +81 0 obj<>endobj +82 0 obj<>endobj +83 0 obj<>endobj +84 0 obj<>endobj +85 0 obj<>endobj +86 0 obj<>endobj +87 0 obj<>endobj +88 0 obj<>endobj +89 0 obj<>endobj +90 0 obj<>endobj +91 0 obj<>endobj +92 0 obj<>endobj +93 0 obj<>endobj +94 0 obj<>endobj +95 0 obj<>endobj +96 0 obj<>endobj +97 0 obj<>endobj +98 0 obj<>endobj +99 0 obj<>endobj +100 0 obj<>endobj +101 0 obj<>endobj +102 0 obj<>endobj +103 0 obj<>endobj +104 0 obj<>endobj +105 0 obj<>endobj +106 0 obj<>endobj +107 0 obj<>endobj +108 0 obj<>endobj +109 0 obj<>endobj +110 0 obj<>endobj +111 0 obj<>endobj +112 0 obj<>endobj +113 0 obj<>endobj +114 0 obj<>endobj +115 0 obj<>endobj +116 0 obj<>endobj +117 0 obj<>endobj +118 0 obj<>endobj +119 0 obj<>endobj +120 0 obj<>endobj +121 0 obj<>endobj +122 0 obj<>endobj +123 0 obj<>endobj +124 0 obj<>endobj +125 0 obj<>endobj +126 0 obj[23 0 R +24 0 R +25 0 R +26 0 R +27 0 R +28 0 R +29 0 R +30 0 R +31 0 R +32 0 R +33 0 R +34 0 R +35 0 R +36 0 R +37 0 R +38 0 R +39 0 R +40 0 R +41 0 R +42 0 R +43 0 R +44 0 R +45 0 R +46 0 R +47 0 R +48 0 R +49 0 R +50 0 R +51 0 R +52 0 R +53 0 R +54 0 R +55 0 R +56 0 R +57 0 R +58 0 R +59 0 R +60 0 R +61 0 R +62 0 R +63 0 R +64 0 R +65 0 R +66 0 R +67 0 R +68 0 R +69 0 R +70 0 R +71 0 R +72 0 R +73 0 R +74 0 R +75 0 R +76 0 R +77 0 R +78 0 R +79 0 R +80 0 R +81 0 R +82 0 R +83 0 R +84 0 R +85 0 R +86 0 R +87 0 R +88 0 R +89 0 R +90 0 R +91 0 R +92 0 R +93 0 R +94 0 R +95 0 R +96 0 R +97 0 R +98 0 R +99 0 R +100 0 R +101 0 R +102 0 R +103 0 R +104 0 R +105 0 R +106 0 R +107 0 R +108 0 R +109 0 R +110 0 R +111 0 R +112 0 R +113 0 R +114 0 R +115 0 R +116 0 R +117 0 R +118 0 R +119 0 R +120 0 R +121 0 R +122 0 R +123 0 R +124 0 R +125 0 R +]endobj +127 0 obj<>endobj +128 0 obj<>endobj +129 0 obj<>endobj +130 0 obj<>endobj +131 0 obj<>endobj +132 0 obj<>endobj +133 0 obj<>endobj +134 0 obj<>endobj +135 0 obj<>endobj +136 0 obj<>endobj +137 0 obj<>endobj +138 0 obj<>endobj +139 0 obj<>endobj +140 0 obj<>endobj +141 0 obj<>endobj +142 0 obj<>endobj +143 0 obj<>endobj +144 0 obj<>endobj +145 0 obj<>endobj +146 0 obj<>endobj +147 0 obj<>endobj +148 0 obj<>endobj +149 0 obj<>endobj +150 0 obj<>endobj +151 0 obj[127 0 R +128 0 R +129 0 R +130 0 R +131 0 R +132 0 R +133 0 R +134 0 R +135 0 R +136 0 R +137 0 R +138 0 R +139 0 R +140 0 R +141 0 R +142 0 R +143 0 R +144 0 R +145 0 R +146 0 R +147 0 R +148 0 R +149 0 R +150 0 R +]endobj +152 0 obj<>endobj +153 0 obj<>endobj +154 0 obj<>endobj +155 0 obj<>endobj +156 0 obj<>endobj +157 0 obj<>endobj +158 0 obj<>endobj +159 0 obj<>endobj +160 0 obj<>endobj +161 0 obj<>endobj +162 0 obj<>endobj +163 0 obj<>endobj +164 0 obj<>endobj +165 0 obj<>endobj +166 0 obj<>endobj +167 0 obj<>endobj +168 0 obj<>endobj +169 0 obj<>endobj +170 0 obj<>endobj +171 0 obj<>endobj +172 0 obj<>endobj +173 0 obj<>endobj +174 0 obj<>endobj +175 0 obj<>endobj +176 0 obj<>endobj +177 0 obj<>endobj +178 0 obj<>endobj +179 0 obj<>endobj +180 0 obj<>endobj +181 0 obj<>endobj +182 0 obj<>endobj +183 0 obj<>endobj +184 0 obj<>endobj +185 0 obj<>endobj +186 0 obj<>endobj +187 0 obj<>endobj +188 0 obj<>endobj +189 0 obj<>endobj +190 0 obj<>endobj +191 0 obj<>endobj +192 0 obj<>endobj +193 0 obj<>endobj +194 0 obj<>endobj +195 0 obj<>endobj +196 0 obj<>endobj +197 0 obj<>endobj +198 0 obj<>endobj +199 0 obj<>endobj +200 0 obj<>endobj +201 0 obj<>endobj +202 0 obj<>endobj +203 0 obj<>endobj +204 0 obj<>endobj +205 0 obj<>endobj +206 0 obj<>endobj +207 0 obj<>endobj +208 0 obj<>>>>>endobj +209 0 obj<>stream +xÚíßÜ8rÇ¥nõ‹Ÿ4³îwNH€ØîOÛg 4?´‰(IòäÁ¸õå6Ø»ÍÙÞ÷ß§M·~RU‘’¨¹á Ï ÕâG,~«HÕ}q%V›ÿ®Ä‡kñî½øÃŸ_Üɱ|ñWñnõ»7v|÷þý›•øÝÇ7×âúúêÍ֧ͮ·÷Ù¼ýô6ý×;±þçÕ®¼Û•÷»òqWîwåÇ]ù—ÿ|ûI|ÿúۗ·ÿ.nÞ]½ý7±¾ºz{÷âF|zx‘?ÍÏ\fE>\/‹‹³mÙücqó0v.y¿8 =U9;¿|'—¼¾P#à7#ã’×mLåü2 ê€v3®û \üEì8×]èñÊùÚa®k.•MsgúÊnŸY溞yù!vŒ+»ð¬ÿÒ)®kÏZ™¬á’³Y.á2Ö »]f‰K^x֋ÿjp®,ôº(? ÌuçuT&ñ\W^gÅ_ÆeY-ÛX›òj.zž‹`खËËÞ¹zÁbÁ°8`0,8-|ñ€q`yÞ²'®Îý–™ƒfsõŒµ‹ûàZy½—I\·ÞeÚ9Wê R^v̕…ÃpDÜWx–vÀ¤¡0Í 1:Wæ ZÖ]q…Ãr!‡ŒÀ!s¼ŒÃs‘ÅžÈ%‡Çòü¸„\^`+õœ(kË\2tƒkb™kå9RæV¹Rϙ[ärÅ +QNŒÀy•µ5®Ì%¬Vé€ñ‰*ꀊ&ê€QEx­Çr%®aµtŒOãQ#ÔxŒsÆqI±ãz£Æ#FŒÏ%£Fô×]gç‹Å«‡m¹Û|è¶Ã —îòÏ_ÕùöDgÝw—ߐô/ï/ºé0躻Î[§JwhK®U7]U쵅õ°:ì.Bú±äæ¯Ù\ìPƒ–.Î$›r¹¸¡==7cMb&³»XéԜ. ˜\¬@ž› Éè2ŸÇ•t£í»lÉâ +û²Á£7 ­H=Ø_Õ0I{ç$¬\¢·¡Åϼ +è\ÙXd0ŸÎEyßÎIa¬Í\aÁ¦T®d#ä˜bLäCaÁæ4®ÌЇ䂅F. ìM¼^æVKjdˆ`-’·ŒE:}5§p%£²2¸9XR ?¶ÏEhAŒç’æAšiÉø†¨ç‚A׾ܲ ¬ÌP&yGEp lÈl'ƒ‹6æX®h(‡Ìå –‹`†Ó¼Ã"x†æf؝R4q‰ãZ9a…„–8.´&>Š+Ø#3lá«aw^p6Ãp…nˆEë'®”˜ ×aq;WäŠhP:lÙÎ:¢ñ¤ö­\©[݅ì°I+WäXw!}XÜÆ:Ö]È'=oáʜqÉ´&-\‰s݅‹'-\±х–²¸‘K:Ø]¸1¿läJì.Ü2RÐȅTy¿W,”M¹B‡"C¢r4qaU¾g,ÔðX7p!U>è›+'ÙpU~Ý;§ \¬­± q¢çJ]y´ ÅZ.pQäÑh©åŽªΔf:.éªjà†þTǕÒBò';ýT1öÇßÃá™&%UN±~~…o°‚¨9Šk®å’¥‡5%´]k¬á´X£‘kªå:ܦ¨sÇ!ñ8Ã+Àqyz.(¨W†7ڒ€3¼–H®¥–++<Àš!f”j. :¯f®@˵·½É©&–”~¢æDçÕÌ5Ñs´BRf=ègŒàp‰åz4.×IÛS¼b”>VqeÔª…k®å:‰`DY+I°ès¯Ï5ÕsE(¤L¾3¬ y®] +å[¸<=Wzø¬Œb†ˆ¨¸B¢¶r-µ\û{Íö¿Â/Ùµ +ÛTÁ%©fØÊè¹V{ QßC5Znó\)Õ [¹|=×þfÄéAŠD {åË5=ÖVríãŒºrŒŒê•'9–k>ʓ’« R”YªÀÙPecŽçŠƒš+aÍR[CÄY+#›a3WZ©qIÖbI‚Ó5 ÊÆ$ÇsÉG³PsMŠ´X’áZĹr@àÚ5<Ðs%¬5;œÐQ6–.8ÜFÃ%Ykv­­¬q1Ò›¹²ƒ(h¸M$®ÙE¨&M6&9…+?(½Ž 8N ʤ€&3×Aéu\§¿R”'šl,i\¥×q…œñ%Qϸ‚(®ƒÒk¸RÞFˆ‘l E"×Aé5\o±¿íùOË\’1¼Z¹öJ¯á +y›3æáI6–T®½Ò«¹2æ.F‚qÌ@ZÛÈ©\{¥WsÞ Ì"©2WÄ^í\;¥Ws fæŽÄ8f DQkgݑ~^¹`b›À­K\¬Mårl¥àÚµ^¨¸öv/!‡@4(QT¬~tqÑ@ü2שU.±×dA7Ä"àVA™kY|4U.Ðp=va7» 3+r!Öl¦“˜uRáÊ4\Ɂ'£b‚ Èá\cÓúÕõÏ:×êñ! w+ў¶Ä%8²QÚ–_TàŠ”\ò؂Ù%®€jM"(,«\©’+9VNè±/BNô¾ûJ›«¢fÖüT•kuÔIÏ· +ñ\Ç+Ÿn៕áqE™«ð‰‚ûŠöðÑáãKfu®DÁULE‰È†¸j0€—Ã5F›â:W¦à*êMJž„žkŒšMLó:×ÁVK\aqÀ’'aò¡¹¸K6ªóxzO1/.r•3¢Vd4=U¬RnUN±ŽQäŠJ†túh9ÔNþNï5y•+¹d+,Y^ÖAª& £^½d»Ÿúç=!¥r%L9|,ûÁêW{4ïç£*€•ùÉ(¹/Šrž+äEQ®sI9t˜+3”CW¹Rntè8WòÔäðÀ±£C·¹VüèÐi.ñÔdþÀ>59 Wí"-W£ +m8|Eã=¯TçÃpÕ.*V?ÝŵΠç_sekÇù0\µ‹´\À£ruÇhVUkM<ˆ6«z‘WŽæ +T¿õcM«ÇùP\Ջ´\‘E®µºcu«ÇùP\Ջ´\+~x˜« N³¼_kbõ8Š«zQXIS=r k\~¬á*„ª¥&VŽóá¸*ñ¹&H.YøíÁ/–=æê&VŽóá¸*‰‚b—¸B;\…üÃb¼±_öÔM¬çÃqU.ªÅQ –+Èqó”\ÅUx?”¢‰;Ѧr•/ZU#¢èÀåu˕6q•ó!¹g‹M\a¹fF\™.ž?•‚ÈU¾(©•pÏ%;撚SŠã|H®òEiE²¥‡åšqå\Àá*]$+¡yâWÆá*_–˜8pµç.;ä*çÃr•/ŠÉø®tX®ˆÃUº(9í*ŸyçJ9\¥‹d±•é1Þ0™VZà’®òEâ´ÿuç¸â.¹ŠÇùÐ\勒Ú~¥ \ ‡«|Q%;.“é2Š+læÊ8\å‹Ê3ã`åWá8ž«rQ©Ãâ¨G®µ¾‰‡«|Q9v\­Ë¾!—ðŠK´3uÀOåª\t[œ,&ýpß i¢äpU/º+,EXàr§Üïò8½¾•k,9°²xfڗÙF—Û»çÏ\Ï\càš>Q®`œ\á3×3×3×3×3ŽköÌõÌÕ=—gε™ù Ï•RêËu·{‡™‰i.¥îÀ\Õãkå— Þ0§¨«Þ PïTyŠƒRÚÖs‰ZúF9O¿¸=U¯ËàZ—C;⺭ÏhÊ/óÊN›·˜U­\Ëòí†K*v”Ê/4LŽKüuò¨•kÞ¨¦Ö¢8À*镺 ®Y^šÝp…ª­2(Žƒ°”&S­Ëà +Ê–Ò Wö¸ñtV¬[|uíi·^Y—Á5)ݺ®ä¸Q(¯ +7-Hà)»BY—Ï•vÉv¬W'ïRpY§äsM]Õ2¿ú®å흤K.QyU' ,¼YS—Æå·O7ƒxÒWX\†¥?OÜP—Æ59>ލË$ž/ýNjq`i9I[U—Ä5=>ŽÍ“ úáJN?S` œ¤­ªKâ +ŠnfÆÕ’~xüsv¶)ó‚XŅ3Rúº$®íù¯ãcšwÊ5ÑýaËSH*nZêÇs‰Ã Ýáeg\¡.ç°§œ`†Ô<×êðyÛO^wƵך¸qRFÚº$®è C[K;ã:ìuž¯ÕÖ.“âQεuI\pÊ~õóθŽ!z­µû/~ ¾X_WÉUOìÜQ$‡ñºu_ÝqòA*­½ÍÑëëR¸Òƒ¬¶lÆÕ´¯W¬Wz/qRÏ¢ÕÖ¥pe‡·nِ«i6Ržã(MŽãÖº.é_ˆ>kæ2Ú_–ÚÌRQËjÑ×%påǼûmw\•,Z?®õd€¨KáÚ;æ[ð¢­2…êKætu)\{ǜî||—\ak¹TªdÓÆº8®½cNwõ͸Zó¾îBÕ¨ʇ¢®‹÷Ë;7oÿï·pÙÈg»¿¨OjÍ$GU—À•ì,p疻ç:µvZ ¥Ö¨º®½cÞ¹å>¸Ea¢4Mu \{Ǽsˆ\Øw‹¦ÍbÐT—À%½Ø¬/®Sâu;W¥.kï˜÷"ÙÈe’½}•̲습\Mu)\œd§õÓN¸ÊîZ;uu)\ÉðÓ½c4äŠqë‡-\Mu)\۞N¼ã‹ê:㚔lËoäÒÕ¥pÁþ0¬ßÆerîF”þ,u¾©.…+ٟ¬™˜s-›§_óâÁÀ×ðû8ž¹àZ=ÁÀ÷=>ËQrÁåJž`€hø½fC•¶—½Î ¿‡n¨ÒÖä%î{ ¤;\ÎRmR~/çP%Bq…£ 8ÚB ì÷Þºpˆ6ûB~O±k+ma› ¿WÚµ€ÃCqÁØÙêo‘ßoîXÀ‘â¸F÷}ôIk7&ÚrÎ1Cë°Œ¹:ç˜W­2yq΁‰V·wàœ [{Pü®9°ö°Pöê˜ËÚÕPúâØÌ2mWo@ùÇXÒÞX@=ÇXÔn\€2XÇf`«ö¨Pq¤cL´‹à„Ó-¡G´pŽÎ)¡Ï¶¸žuJèS„Naœz@逫ê”ÐGˆ¦²k]z0-@E—"ú°Ý}=rÉ ½ÄH7äX¡ŸF—.1AL0#!—C‚ar¬Ð{c‘C¿È•ŽGQ†9Zè‰3TÄ9Z胑Èá¬È…zG„Pv9ZèŽJ­ž®Gˆ˜}¸’‘DR­B°ßJ€/ôÁ(dcRæBýd²”¹K7þ(dcVá㎧€NDùðo¸NGŠô²@¸Âሐm„œ ˆ,f·ªÀ´Ê…D<3v¹rŠ ÎÜ^ËW4‚†> +„õBzôYkÈIÂ1ôC¿£r’p <ÀÚýTÁ%œ`øÄ; ïÐl…(Ó„c؆€ä`)~*¤XyàFØ}’Š"vÁ!' +ǀŒ²I´~tFÙCâ…C.rD„ÆQG‡\ä ,µq`¨ôe±§TzҊ4P/Né¥i@UÒÁVÛ$IӀ:43D„-Mµ\+w ‘¶ü9}€Í5Ãb,d—>!&4Cò g C\ў7ЭxC”ÄÐÈSœa 1!>nÈl€Q‡äœ¸h†¥™pLÿ“•„ú°!ç °Þg͂ªf³XÏI–)Ùû@Î`=»°ˆ<6€Õå=+‡¤·XC´gå`D­À™n÷súÈÎòHÏ1GÊ0 à Ò^¥~ÅðÀ|<=J½äWÂâòüjg1,¾)hãbv˜çÇwVóܨ•+ò¸ÿ¥ó÷‚5Œs.éñË9ʳ Þ§/¸ :l;Î.ÛÌñžIÕ2}hç2é°=ڃþ³¯CöçÎ ¹¨Ó0¥A^>ÔúMÞ/B“Ç•›režrv¾X,^=lÊýbq~ÚܘËF‡Y/mù.é ×Ü—™$Ò]8.÷:li…˹k_úÂqɱu’‹°kÓGA,è!¹òÐ%®µ=®t\݅æb­tt¤ñ±M®Ì®yn“Ë­Çmoà¹d8§qq—p —ҁÝï¥pÉÑX!ËKDo’¸·D|֍+‰R¹Ž ØD®A-‘’ûBåÒ;S¶Ÿ¨\ö¤¤92×`CŒ–öBçhˆË\à 1âÞ.ƒk!FÍ2àpQ҇Р6WïÚAO•ãqõ¬Œ @&—îJ¡ WŸ¢ÈJærõÆË$cs1Ò~zq\Æ\=MƘ' ¸úðÏ>÷ … W÷¦ÈÏÒ4âêÌ ùԌ«[U4I6äêÒAå@›ruf–ŒoÌEΡîhbbŸ«‹i‹aºº.û²h~n +W.íÚâ¥y‹ìpmlÑ^—MÖ¹;\¹¼p§³lrYê²óuîW.¯e𕭶Øäâ§V¨.íµÄ.—Az5"u{H..™]ª.¸8dç¯l·¡ .b^¼¿èà=ÝpmÊ.;Þ?¿éäöqíz­Å Ï]Ý»K®]·]/ÎÔýtùÐå}»æÚwÜö„Ãââl[΋ˇ‡ÎoÙ ×âO/’wòÅÛ?Š«BþQ\¯ß|7«77BþôéíR¼÷9d"ûõßÿïó×/âö§?ÿü—Ÿ¿}ÿúùû¯_¿‰ßþËoŸùGùߛO¹WWÛO¹ú°¯¯Þ½¹Þ~Êöê×Ùíï__½Y½Ym+¾þ¸¹Éëë÷û»ÄŸ¿ýíôéðõן~ûÃ÷o»z7ïÞ¼/|Яÿó·¯?ÿן¾oÚúñÃëÍÿ>þ“¸ýå‘nùM¤_¾}ùú¿_~Ú^Ë ÙÿbNô+endstream +endobj +210 0 obj +6321 +endobj +211 0 obj<>>>>>endobj +212 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +213 0 obj +31 +endobj +214 0 obj<>>>>>endobj +215 0 obj<>stream +xÚmTMoâ0½ó+F=T²(”ãÒ/!µÝl“V{àb’IqëØ©í€Ø_¿3I +”­rqìç™÷ÞÌø£€¾¦CM -:ó¤óãvá ’Æá8˜Âd:†$ëFs‘b/y#ĐýÒ §ÁQÉZ:p&÷[aDVH-·Âë º +Jk62CG ©=Úc˜4¤Î-š5­À¯®LQÐïóãâ3@?5#"õ+Ä;籀e÷ìê9ŠÏ–=xAë8H èk˜“¶‹à’¹SŒÑ,¨µµWmÐn$n¿j$ÜpÒà’¯Là4÷^™€ÒX/V +‘ŒQbGZYß]/&`JdÍtèê.€…‡µp'Wˆ2Ü ¢¬vp#ÜâOŸ#k²*õ¼a…ñä=8/t&lv àŒªö¶ +¥Ô—‡Ð'y+GÀ~´q9Z½/|æhßQáR²†6úJj„º´Ü1.h£~ºX‡£ÐM¨ã4úƒ™¤Æ›Ô(*åâ&¹í/¢ˆŠ)øJ8ê0æO©Ä+ãkyðfVµø¨°¢¤@Å:‘sϼ¢¶é®r—Ýûèúžn¯Âp:[öÎ!¦& ótN¼"̕Iß ?Ìù”3ü,˘6‰sÙR¥ÌÜîʙ“”®*¹¨h[é×`‘êD?y¥S.„PÒï¾õGd™²ekìû~PVÖlKf‘q>N­,ýAºzCÖÂÎ¢èšÆ O–áQ˜úœ{å{®D’†”òª DY*™ŠæB¥3lš÷{Ƥžªžªª™€´rÞò/åÞ´ƒhr¸{|†»õú²›VÖ¢öj Q“ÿƒÑ²w—Mô\\¦\Ò¬=-"já!¥ýr“e<ŸÊ´Ñý#ÛZ[]û4\>´/ÃÑ«7¾3:¤Ýÿo’ÎïÎ?ÅÁ´yendstream +endobj +216 0 obj +698 +endobj +217 0 obj<>>>>>endobj +218 0 obj<>stream +xڝ’AOà †ïýßqZ íhçms.ñ°¸Y¼y!”u˜"Ð-úë…u‹Î¸Ã \€—ç}?>Þ#©2&n@㤺ñg¤(´Í5ï;¡<í„ÙI±¿¡o^›Bƒ2Î&ƒ’n¥«7nόVwRIë sÚXè˜êY ^¡MÔü5Hå4¸­€n[½—ª+¸“ZÙ»Á…]p™`ˆ1Iò`ôŠIç1FbXO ”êÃ:ÑýJÌ¿£Ìã.€¼ÌzÙÖÄT Ê:Ö¶ayÿ²ª®‚e§TÂÀº½€%S¬áA¯å”÷OÔøG¦)çº?@QyM ‚Æüyº þN(ªS{§çí]Ú 1ÂyhVÓp‡½¬,!½ø™h´Ž¾ †ºendstream +endobj +219 0 obj +307 +endobj +220 0 obj<>>>>>endobj +221 0 obj<>stream +xڝUMsÛ6½ëWìў‘}8Šul2É´‡ÔêXnsð"—"b`PŠþ}߂ÔG¨L2ÓÑE$w÷½}ûøw4¥ ~Sz7£ù‚òzô~=zóiIÓ%­KšMٜïîi]ÜLéŽV^ۨ햞!rM;ö;ÍûÛõW¤ÝÓt*iw]ÞÝü~’¥Ôu¥å•j"{j¼Ûé‚)K®Ï'WRåö+¦®®¥ç?ÿør…·wþ5dH¾Ío¨å‰ÏI+ï6†ëïÉuÁ þä<Xù@]È¢¹ͱJó£*7T©@Qۖ‹Äõeöv‘ѳ5ú•é³Î½ ®Œò–þѶpûþò³ÊŸÆ]ƒRÅ:© ^Óy6^!*[(_°/UΒ: ´X¼*å]Û4Î÷4StÈè7È·MRgÚ¨SÏ;íÚ`¤vJ…–Æ3€~Ïþ• #ÊGÑÿ>kÑqÀè<'€Ú…˜j+Ã6f}±Ùâ4ŒÀ×É=i2Úò‰6½ÜDþÉYsx¹•~W¨ý”{ÝÄ« !·õª©t^nÇéy¯c5ÔÑÕL¹Sßt§ÇrxnÚªwb¢¨l!¯ì–ÅŠ'<)\j“Ä®U„¸¿»=ôc”ÉU‹öXåCܝòrH%) Ú5ìՅ „\Ô§B—%{‰è„T•|‹–ÇTÖ¸æbÔÔÂëp_(ȁ¯Â¢šçšáÁÖykbFëJEHUo0“NËmt­#^ì`¤Z* 0ó6DˆÜ£Š]·GÄÞø’£Do•ăvŒ@f°kj›K+§H×,`ªŸc±Î‡ç ½â˜Ñ[é@,ÍXùl{FV¬$° †cë-†ñ´ÁÁW—’„Kß}‡l™‹ ÃBª¬ñj  + Å~kW´Fyqª$œO @õ¶#@àäÎ&Ò'6(¹,ù„+ß\zž>>>>>endobj +224 0 obj<>stream +xڍWÁRÜ8½ó}$UŒa äBX HílÆ©½pÑÈ2£Œ-9’ŒwòõûZ²=ŒC¨­Pa<’ZÝï½~m~Ìéÿæôþœd}p•ß| ùÙ%å%ÖÎ/.²sʋÃ|­(WrmleŸ¶ïòïØxFóyÚ6{ÿ!mûôm±$íi%¼*¨m¬!aHÕÊ=ióDw&(gT „)„+HŠªÂ΀ðãâÂixûÂÙ`¥­ŽÈ:º[,2þÖñ•2œ®ž¿ÏNùjU¯œˆµÚRa*ãɖÔp,åE1~öÊ=ãW-L[ +Z§œ?Š;:]UˆM¾mëB +ƹõo /Z:ëm&7ÿ£Ma;\×('bâ~냪³~ßéyvÆû8ùB•Ú(ObAÓWI%ªl†ÚQd§ ~#QዋôÝ®ü^=¶ Ú¢ÜJoÕªÐb’ ×?Õ9åmÕòÖT¬·|cXgôÀAà%憜€ g-A"`iy©²Ìٖ)± ãuÁN®îsô´nMáTáù\XÛÖ#…ÈP­+Æ£ی¾™XƒEL÷2‡µíîJɈ +™÷ ᠔ÊûɭҚàX7¢E(*Å®ne¤Û6é¹VR·rMµu _IˆbÇŀ¶*t°øÁ%¶ +¥° ×ÈÝn!YÎBʝ0žÓßWømž/ލ[kä0|lèˆR§V½nñ8•þK +2Ê×8ŠX’¼Ö¹¥g­:t†lk ñH2Àç֓6C¾æ•ºÆ†i=Àøõjíbv+‡ •›bT>ë"Ê^Úº©TPLåñ<;7`[‡‘»cW€ANȌɶ »IZ£“<¨DF×úIùðZ¨üaùB£ˆg¡+±ª¢²e· f!vœ-'÷rµYrǗ6ÊþѸGïþÖÚ!Ìa?þaF÷Ñ07°D€R'_Ôý£…¹µõŠm1—¬'`&’ImAx¯Ÿ ¶e‰ðÙVÂÁ×<Î&4[ßFUôø®Oƒ$6ðZ<«Ñ¹ÖJ-¸ÐN‡5˶žzw'›!û%GëG{HÛh՛8®´N‡í[<|ªp¥òoϱÑcР•’¡§œFOÛÛNjB‚|-ú@„ ¾¸-v;Œ‚„+÷l©ŸŽ™‡ÖÔ&nŽqÞªöFWœïo«íדi°.|ê{Ñ4ÕÐ"H,L#ÌD˜YÄ¢ŒîͤÙ6ÌÍ R%ϕ,Íñ4®vE3²Sj“½D b&¬OU&'6K’Ñk.՞ÑÒÖÃþØß/ëSÂæB—%‚áædm>õb½>¤¢81¦gsFñòßæûgÔK!j͂4~㳩®„ܨÔH/„0f=fkû áºfù FÑmžÑ3Þ¾ÈôRé!Kô"ˆAEVoZòÌžÃ쓬k®<âzD·‹ÙŸǧÃãâúføÈ€žoñ9{êqvWhWZ æ¥tº ñìîú*<r¿Ád·ü–†$¿Þ-ð!R9Ðþ"6Ä8“‹“(P¥•µhz1ôo6;}ºtóÿ‚n•è`ߊ`ìÐU±Ðˆ¨(šI‚i|sÂÄî¬Û`8‹ø|¯ÂµvPØ$ÿÇÏM³´¸/<¾;¢ej™/€…ºÂKÙ&E~Àëeê<¬_ UC©ã›To—½ç§gˆ~~y™làúëǛúŠE.ñžÛqK~,jm´Gc0@_ðÖ,*Ž3KÇg§'|úŒ¿;;¹Ìø¯ŠWÿbøœü}ðmPendstream +endobj +225 0 obj +1372 +endobj +226 0 obj<>>>>>endobj +227 0 obj<>stream +xڅUMsÓ0½çW,¹PfÓ$%mo|` + Ã¥U–kQY2’ŒÉ¿ç­d‡4…azh-íîÛ}ï­úc² cü,ètI«5Éfòr3yúæœϊ3ÚT¸[ŸžkڔG—^Û¨<]xýSùðdó‘'´Xä¸ùêü~\™ãH[zõõòФ³A‡H®"gÿjœWTi9,´JêJKŠŽµ¹H‘Sµ•¦+UÀEMkÔxÏMz±*– !©ržÞªÞ¨ç—BÞ _Ò”¯" [҅ +wü÷P%ô­Ö¨k†¾©tÀ³.Ò­²Ê‹ˆŽÛ¨aÈu±íâ4c–ºª”WvW–Ê„é˜ë•ª 1•«]O[ב–z¯q‚/O®·»ô‘Bî8ß:N=€Žµjp ޘ¬" ³/!Ks‘ŸT읿ÓööêeLiDhÛYP£È8‰ñÃ6D +h'ºè5ŽÍ–B³’zkrˆ÷Cè.ßfø‚6àù`Tp}H„` b×&› h8K¤ÜsGê± ƒnc_a/š³–Ð&´Îp²T€;h~äSã0Ä»ô‰5·é’g¥ì<–ɾ`0Ÿ§›qÏ+þ؀%¾]R*ðÉ=ìá뻉QP©´(døXLýÂ…L3w8‰3gÌ”k: ”Q2¦€1ñf;,Ùö!z_kYtcfõúH·M‡üçLÞbÊdÞ;ZN‹ë'C¹å:-m­0Us?5¯nvÜzpܑÆk‰½>>>>>endobj +230 0 obj<>stream +xÚ-‹A‚0D÷=Å,uQäWnQdg‚RÐHIj¤Äߪ×ת™Ừ¼» äŸÖeêe[-VíDÐ#H™B¥rèaќêVCbwîzôó_†-êarޅÈ&Îp0þanK}ò'Ë¿]&VP™UøîŽ–Ѱ{ZéÝkqoµ-']endstream +endobj +231 0 obj +131 +endobj +232 0 obj<>>>/Annots 17 0 R>>endobj +233 0 obj<>stream +xڍUÛrÚ0}ç+ö­é ›;y iÈÐi34éeú"lÔX’#ÉaøûîJ†8iÒv4±Ù=:g÷ìæ¡•@ŒŸÆ=è •­ÙºÕO!™Â:‡d<ކ0`õ ³J™P[`*ƒ…²Ž=^Þ-Wï׿0uIB©Ûéâȧ¯wÂBºc¥ãìNï-àNÆ@=¢ˆàv.µ”ZÁÝÍâ,PŽîY¬ã2‚E]3ü˜ãI…«u+ŽbTEGBÇí5ô{ýh +ýdŠ\$*D½ú©€iŽ1¤&ºŠ™dÂ:#6•È"7ZV(ö|V8ކÒè”óŒTЯ–§>Ü Wð¬ oói0@>ãa4iðy%¾!aO°´‹oF`ü(‰Æ/ô>O1Ûc‰ŽUh4—Á,”äC£$$í $®A΢à4&ÜNú +îJW&åàúü>ócè H ¦Þò‡J.¹rö¹Ùb?¢ ïºz‡RÔ¦àâfµ€KHµ,EÆ;ÙÍ7[…6B;Ö¶º° œÅ$úJ–…à¶"Ñ»·b«|³½x´¸ç˜™J9ÀÛU—Ü0ï×Ü&§óGºþh!ô379Cñ…Ø*.ù_jë@ç>,†Xÿ~ÃÒ{®2ûâ^[•Ä1ƒ½p»€‹ƒUÑ0VѪT†×~©ÑVçîgo8‚¯Be8~ôwT#öF¡;s8 +ɶžÂsKä·J(Ü.–m*ީؔöqyu݆å ëÅ|ÞöI?>-fµJ¬gtÚ !{(¡/$EWŽà,š"¨3<«R¼&¯”Ÿ1VwˆàŠÙÚ(w{ÚK£1 +;(¿H¤0e…²¾¸8­ŒA;öÆ"¨­£," ̝·Å0 žÄMyBøËˆG1LȺz ¹Ó?¼=0 FÏ]yÞíâq”g÷Ú·[V›î‰ÔëӗLúxM|¤ÕXƁÀiHêõ)Ù=§•¬¶(³^a‡¦dô¢ÙÜë›;؝瀕dJc¤E/:…@ ŠIQ#P¼t+{d¢`²nÓÕ´;ŸÉÓO¸D†ÿûOh0‰qãø2Œëö|iýíû=endstream +endobj +234 0 obj +831 +endobj +235 0 obj<>>>/Annots 22 0 R>>endobj +236 0 obj<>stream +xڝU]sÓ:}ϯØa†¹a¦–í´ 3÷¡´M JiÍË^[N¶d©!ÿž]9n\ÓޓŒ[ûuέ¾bˆðÃñ˜¾Y5x›.ÓAÄ"|OKLËíî²Æ ­ÄI̒ÝS wäÔó0K§LØ҂B“אæÃ®߄!®l©Óf®Ý"\]¯Ò¯(Ñ.J|rŠ©"ò%ƒpzqL1ƒ¦ˆàxÂÆ´›®ä:s•P–[©È +m*n­ÈÁÕR-Á¢Ñ»ôÃüâã9Ôº°nƒY[í@ ´³*þM@¶âj)j¿‘qKaÉÛ‰¹ X>ìǂÂèêMShýƒmý¿Ñ¤áw2BPÍÓ³ü©±'fe=«›Í† ^oë Ët®lU"!ÏÐz:Æ Z'ДHÄúìÁñ¨!ö\WkY{çŸoî7!ÚóO›È2Rvuý¸³:Óª >éW.²Cô»…,ю«‰s&C¶u.¨YD·„`EÅ íú¶É;ì÷Àn×âùäÓÃK`á>úåuzyÛ¹>R—(¸+-HU[^–È6²,aí¼8|{-Hå_¶5Q‡¡«ÍãDCÏDßìžÿb–K#2«Dò0uúlV2[õøñµé{a6FZY¶ ~ÈÚR/×F*ÿ¥Raþ~DÏþéÓØ¸ÒøÞôr–:kˆA)<?Öûÿ£M¯Éë/»×ý—È ©„ò`GñÐSy7×WGðþæ×t6ù^ü7Ÿ½…R. ÷\`ÛҁS‚à·ªkeñ€üË…(±†rû|‡&_¨TYérñ;jð¸ä¢gúåµììP;»êfLõýϧ󳫻ßH4¿xÒR¨{i´¢Ù +(LÉx€{GEáyÄŒSªQÖ®?ÐU¬sAS/¼fa­+¶Êß¾xÚ~W6:Ì8teÃ;(“ +Ç]+~/öìb¬à««íŸNÃʌL.œ,sßχ˪?­£ý ž5òlï¹»Ë³»wÀÎö߀iu@%»ŒI‚nãQÌ&dq{6M!hÆI["œå•T8™ ǞÕð+ÇK +Ä£t^ü]•л“8a§ÍÝu+¾;ì4é²Þ]­Ÿ?´Nendstream +endobj +237 0 obj +858 +endobj +238 0 obj<>>>>>endobj +239 0 obj<>stream +xڍTIo1¾ó+>EjE¤0¬aɍlUM[2U.¹xÆp3ØÄ dþ}¼Ì jUqñð–oy~~kõÑs¿>& ÇÈ×­ë´Õ½Ÿ¡?LH OûþHÛ +K˜Ó,̎(vžþqé#ôû1¹3'#ŸüCä •´X‘-ڐ²d4ëº8Äs"à‚Ê„ÐÍïŸO „­¥@VÁT‡xQz˜ENŽh'ò£mr°Ÿ¶¿ kµêꌋnn7šâ+îÓ»ElàT]&Sß¡ã[ g‘êC$ç¥\sAT…[®â™5\ŠO]áØ>3x¹UŠ SV û*×+HÉb;zÐN;7Î(¤Zƒ7«Æ â@…rlI +¾1:‰$.kž~ãôó|ñøðøíꯣ8Ð8íxYBn™Ú)nÂØ»cè36Š‹pЕ6là¡cbï¦8óS¥¼(xnKَìÝäš9Ôc @û9{A‚ùéK,%2’¿úc@–%=½ˆfSì`û+r‚¶jظŽrË©«þՖÖ.×G˜(”\׌œRrº¹þ7·& ?•8lw,øÿŒ¡”Ë¥ûpÃ'JJƒ—6•áÖ œi{®;’‚ i—«—ó͝èõ4t±š© (+Â_G©ï]ùïJÂæ$¶ƒõi®Ö‘ óÂ0å½z!^6AÁv¨˜î +‰7Ët¼óŸ= +þd‡oƒRxò£¶t}›œð@0zjƒ5ÒmÏ]yUoÈ´&ÙŒ\Òp2‰;p»˜ß§èD +Íã…9]sáW“©4¾aI&Ë;“Aï_/ßhÚKf)3ÿ}—¶~µ>ùq°endstream +endobj +240 0 obj +640 +endobj +241 0 obj<>>>>>endobj +242 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS042Ñ3R072PIÑp rt QÐUp VÎO+)O,JUpLÉÍÌË,.)J,É/*VðMÌ+MÌÑ Éâ҅hօê64 [ÅÀA¥yy™yé +%©pÓ@J\C¸¹§ü)Nendstream +endobj +243 0 obj +132 +endobj +244 0 obj<>>>>>endobj +245 0 obj<>stream +xڍUaoÚ0ýί8UšÖIHÈ ìÛV±Ó:ёî»›â6±SŸâßïlǰ†n*QûÝ{÷îûy`±•å–5É%–-¢@Øê=X Œó!ԚËÍaLqà¢V@ã¨àÙ!hÝÀZQiü8ºr„b[D2UÃx-\뺦Š/Ņ»³x7NºÃËúr e¨¬ªô'½f£MMêѽԠÇK´†YI²-Ã'„Ñ5X¢ë +%•T·ArÒé(srÖR•ÿ+ˆe’{°ö–À¯ @ª‡Î¤H5iÝõJ—Ì +ä‹=ï{Ü¢Wò¾ÏÃ¥¥ÕæÐÓ*q0zCjmBgÔ¯Vä¿|zàþ¼m^½‰çWÿ5õϜ»Î݈n|”Ü·.¬ø÷ùûôQqv4Óë»ÕÚÏeÝT0í«~½‘“½´[»Hš Ѝ‹Â§Xbá,ܸm;ÚÝMݗw§1ŽINšÎ"8%dN½ÐõN|¿úœLòç,!ÙõðÓ,¹ØÉRôÑÇcHV}ê}æ†÷p§3Xþ(–?{ïBv•SÝ£ÿ놕´Ü÷Âî…6«€^¿KdåŽUôÔ0ÏX÷&›V>Íâ ^xrb5•)¢„¶qãN³yG†C +ûƒ´ô¹=4[¡0>>>>>endobj +248 0 obj<>stream +xÚ­VßoÚ0~ç¯8í‰jãGQŠ4mtݤI«Äª=´}0±S¼9vÛEì¯ß]ⴐ֍  —»ï»ï~Ø?ZôñÁpLß$k/Z½#ˆ"X¤hOFÝ ,x{±p²ø†Æq0¶¹¸—‰¨Öm`ŝτv`s‘ÈT + }«—áêËG0¤R Í2)þ!s^HíDÑÂIRf-õ]ð²´ÄéC'vÄÇú<7…¤Kfe‚?­cJ1'“»«y<ÝeYvãîˆb‹i1z5ŸR¿ð›í1Ñí8±Ð9*Æ»Ü;p¦LªV€—ùvw‰t¶#¬œË§½Þµ·¢ ¬iά]›‚¿½]ëèÑõ”ò½íÂ_$Mª2ÿ—ÿšÏÇù¼.•Aïëâ5š„0›-’³ù ¯Å§Ì+g b<Œi¤rŽÖÙô~xáÊáÓüâ!‡2Ø!p¢¬”PÓÿÖuD …B£b€KÖÀ¿~crêu{{ “*ò§* šÅL˜†¥¦74qn{|›#+(gÙå¦zå-Ü´_ޜ@²BS‚¥˜Øþà +zð_2Ï_WÖA OñšŒ: WmrzçaÑÔ îG‘Î6QN©É'p´Ï–4 +)pæpaŒ(ƒt›&ˆ¸z™ òB¥DòÅýëø†ó=áÑrttmô…XøBÛfl”)=ØéÙò«ìøá/ϱó¾JÍÍÚbÿí,ð–h’G<»<Ÿ5©[ãtµI¾ ·µ¡Â¾=jGV|fy—@h3Î$FýýÖmŒåö +>‹úý2ÉÎéÓ;ëŽ÷œýyΟyðÏQŽ8)dî`Ò¹¶|@§4­2BÆj‡•öñ6pY®•jñ`½¬OV öÌB&¸d`åOñ +„KºXεDUµqåfºgR±%ÂÈ6ƃɤ 8 W^ØZ»ýާ ã™üm “eLóÐgPÑ(çc8¨Ôº*‹;|ü1éBâÙXŸý§D~&êlÞ2¥ à P_ÀO7ÒLÓ )¤ /`•ò”IX¸=aöÄ$@Dƒf5žL*‰/¾Ì>,p˜é6q˜5inWƒ9VÊ3U¶NåŽÔ'ïh@‡£~wåƒç$Ѻ4\¦úT*åy¿h}ný•÷4endstream +endobj +249 0 obj +883 +endobj +250 0 obj<>>>>>endobj +251 0 obj<>stream +xÚÅVQoÛ6~÷¯8š•dɎl÷­­ Ã6x‰Š>Óâ)a*‘*IÙñ¿ß‘’°ª.ñ-XŒs`Ѝò¶g #Äíi¼ü±5š/"ÅGí‚s-vä—+)‰oän˚iV–XB­´%E5’“É_B6pP ìUSr +…?&ƒ>Ïió]D$F4Љ-N÷húæCV_8) ."Q0wA®±R;:>lZ0Ì·ØOd)ÐÎÈѹ?~ÚÜøAh@7Òҟ²ã°;Á˜Ù\U“|X/¯R/?P/§Q‹—‹N»¸/øX2cðiØ<>ĒÚAv«US;¼DÉt¥!Ù²£rèÎ]”x!|¾CçC¢Ò$MÉMO Ü«­×yëøÖCKs#‘ïEYÂÉGåH§à°=xÓBhcíe¸-ñÈ·pÜ2Ûîv»%i‹H6®«ÿxUÔgàf΂¼WŠùu­5²9({asœM)îsÍñ” +@È52׆XcUŬÈIo \¡‘o,µ?a¨«¸¥æ¾!ªIB?«ü^ŠË°ôi‡ŒÚ ZëZ–KxkJÛ·¯çº—¡¶é\xçÒËTuåõjå¯!Bjñs!F.VÇ{û¤Ä¦K‚ô9‰=ÚúÄ-,_¿c,Ã1‡Ó}–iϟƒíƪº~Ùý󘔮;=ʓ¶raNYvÜó.%ïh(Ÿãi¾6Ø uOîáaéÒ/ßËéVȨÍF„®}«øžiÙs9O䫤 ½¾~•AÐ^Ç7ª°{zªÂ{'%ª{ÍèUjào&æ_WAœÌÝm¶H|€OîD\Lóž Xûwާd¾˜÷ÙÄ37q™MþüKŽ0Àendstream +endobj +252 0 obj +915 +endobj +253 0 obj<>>>>>endobj +254 0 obj<>stream +xÚ­TMoÚ@½ó+æR•HÁØ@ ôF[r¨Ô* î-—µ=®­wÉîÄ¿ïŒ×|¹½Tª@Bx>ޛ7óü>H ¦OÓ9ózð9ŒŸbXFHK~6\@Z ?À¸qvœI=.¤™B¸K·”;9å&ñ$šS3JÞY©=ڐpi¶ˆCÖ?ÒõkÏ I8:Jóh£é’ºPÎsèáÀWƒ°nµ8‚óR)yŽ;[“9(…Xê_÷5F¤ÒÜ7B©c‚ÐG(¥B ¥*jGnÏlbb1e²ÅТóÂz,"H+逾Ã²Q K®nF"£ÊFç^í¨yGӀF¢éeà äÆZÌ}Weh„:‚Ñxo°!̾‡Îã€DÉ0אÄuâmØÑ|»‹‚žKHHgR4nŜq¿U« Ó2|Å-ñá­Èð­#pYF|ÙCZ6wÁaPý¶bØvî%Ú¨Ÿ˜›º¦dwÚ†ÌnEçuòÐZÔ4g7ú=%º“ߣ:~êØü¢àIÐäêx•ÌÆfïv— úýÇÓ%¨‡¿t“ü€o$—¬hÓ^Fföxâ|¹Ð!yÃìvgˆóæ5®ô¥ ¼)Ê®µçÛ üÞU^mçP‘…@z²’–®B¶©qÌZ‰=R/ÔáÂÿ´ïöPQœ½R7Ž–Ö=ÀZ0A-tŽ`ôøhü + ) ‘{!Uûn"Û– g$@ˆ0¤)À”­3;»>>>>>endobj +257 0 obj<>stream +xڅT]Ú0|çW¬NªJ88ú֞8µ½Ò’û&qˆÛÄvm”ß];É݅û2agvg<›£fø‰a=‡Å +Òjô5Mï6o É!^/`µ^B’—0Ò y„}c¯à“ìÈ+.ݧä–Ç›n²XÎ"M +a!-˜v܀-ÔÙ~A£jH™„TÉ\kÃÁnv{°Üœ¸‰+sÝï I7ó¶`òH£xLËÀœPîDÉíópEÀ/e *÷°Ð¥ïÐ9¡á4¥J™ãé«ã¬eOOÌLÓZÛ)៷C& O2M?eʽւ8T,ãÀ¨gŠќfJI ÊWÀ|_.9öÆG†[njš‡O2#„C෇Xq” õ¨mgŽ­µ.rÙÔí­¯²HQd‹ž«Ï]ن`9e¥§ècúñ¢iËÑO¾½O¶¿ !‚îJœò $3 úf‡Ú_…ˆ/Kdøé_¹ !…‹²W/ÎÂ'Yu.õˆþ]Ô\²sÝÚ¯äÀTêtÂ?•™ôîënw¬ß·²ðJ+Cv¼å{e*ô§ ±ÐµÃ܆t <ºž%D{)®ʏà{N ü˜A)þúXv¥E~t•jÊr ½‹-τ{oü)‹^Z!š:jÉç«àÌÞç “ŸÎ\—pÉÏOÔ>ÎÇ$†ž»¾ŽimÞn5hn*a-ÆÌ¶Ù¾ybð<üþ;o¹^âõͨ8¾¦Ûdôkô9åšõendstream +endobj +258 0 obj +587 +endobj +259 0 obj<>>>>>endobj +260 0 obj<>stream +xÚ¥VÛrÛ6}×Wl2‘§/’BÉy‹kš™4ã&ì›_`´P“ €fô÷ÝH]ÙS·#ÍH{9çì‚ORHð“Â"£oQO®óI¼Ià*šC^ÒZ¶^AΧù_“fiJo ~äÒ-ƛù`½\àoBq©u|ÏLìê&í]fËhŒàæk~ó¶gi²>ø.¶µæÀ~5Ý7±NÿS€x³r_b”uŠû³ÅU”‘M¾ +#2õ ÀmTR (´rL*©üÚ x˜æ¢n>Isêw +ˆ(œ| Õ¹cEÛX¡ër|Òioh³Ã'æ`§Û·ObÀ Åt #˜üý¨fäiorÂTŸëÿdj áryp#«ªÝ%a3Ηb…y˜Ý:‚” ”ÒX‡ûˆ”V K\”–hœ0Qté; ¡gIq¾ +×ió@ùÐFNKNh.JÖVŽØ<œ!|üóöûf%­ÊB© «>]ª-&Y²B`] +Õf‹tDÑÝÔ#à˜âÌpø|{ë-ï."øÀkT•u}*e«úH̐òj‰Ô’*]°ê$•Nº­Ï›5Ñ‘¨‚QÜ«Q¬FÅ¡aÖbÊ<êæY@ñséuÅ1Ú£ð¡(*°k²ôŒ»ì©½¥¯>d%¸tç„?¡|HÝ1!?¯óRVâ@ñ"¨ŒH›Òn¦þÙþ¸ m# +YJ䊪|µÄ4‘G\µJ#¸Vr´?ËÜM‘ë» B +¦Fè³Êjԓk› ­“˜ä÷·<ßû['è-¹pèX”ŒòÞgщûÃÆ(t'ªê%X¿ø^ì¹ÏAÊ£QÉ87¤"¯?¬ðÄÜâÃäÎ*év}ž>*êEn#:†Ž)Ï+2©»“†ÑªÚ…öSÝ7T͊-÷žAÂý_Ò ¤óU”à'}ß7þÑX¤³¨R¡9ãôypÏ·ì¾ÔqòbS±mïñï%֋=n[*f»€ %5Lµ#ÞFÊRÚ„·v|æ—dwmtgÅk{ú¹SÇò£ëÙè +§âVÛÐMx‰ÔZI¼>qXQsQk'G%u8u÷n#HoÝÚ_½£²Ç- [Ý ê½A9ý aý|¼ïÀuŸo:_¢³l•E rùéۇM³Ðáßué:ùG÷6~gªeUx!òÇg«¹¿ӌ—É*z.dºÖµaøª°Á™êÂM>ùcò3Rò‚endstream +endobj +261 0 obj +955 +endobj +262 0 obj<>>>>>endobj +263 0 obj<>stream +xÚ­VQoÛ8 ~ϯàc4Nì¤I:¤ÛЏ[s« 쀾Ȳ¼h³%O’›åß)Ùiífz7“"?’ßGùû(†~bX%0_¯F—éhzuq iA–ëE´†4¼Iß¿~•~Eó¢5Ï`’,£YÿÑ Tu`…·ÖèA•+áöÚ|‹€ æ¢`Mé(b;f‘v>9?ž|‡ð÷;Éw°—Ø`Bu„$U¡MŜÄî;=€Dã°M†€lÛò' 9rà× ¹.üô˜ØjƇíäî3ij(™C$¬M&…)í YœA¼<m` ™töìˆØw‚ݏé¸TP0îN œ NNÔTâý«ÐJÑõ3ÖFg¥¨€Õµ`ÆÏ0PÈÂÇoÇÑì‘x礎Žx¡Ôm‹ðVðÆHwø)÷ÞÞmo)éƒÌ‘E×[߇\WLª‰"AdÌbjÆ9͚kåŒ.½Ó%³’k'ÊI憤é¶=¤Í!0¼Ðe©÷^&V4ùƒ·×’¨m[ÙÁ«Å÷Ò +ƒêiIÈ[xÉ#yxŸ,Wò¦,¯ä³¢&ÒúøwŸ®3ýšCZQ#Gȓ\‰éƒIÒ8 …ëªÂ‰uÂá}î*;‰ˆ—ÌZaÿ¦v®6ä |ÕÙoAAq^˜ºþ;› L%:¢oè¶ÁP†$sì®ïÂèêÔ¥6m¬™Ú:NySÛi®ùiaÇ[:w4üOⲍ1ºA2y4ò@hGg‹R´ÜȌ$"PYý{$(e 1 RÈ/ ÌÅë˾î0^„ýAk®óîÇôç=1½éY7¸•ÒC-ÂÞzfzK̄[Ó÷Œ½?7&Çzß u8ÛЪèé1\Ñ ÐÖO@¾Á'+Üݳ(îCŸvØß„j×më×Ēå|… Ÿ6W)rÏ/š[]¸=1dӊ{¦ñÆø‹©†ùü“8YÉVx½_Fº ÅŠÞª¼!^у÷éèïÑ¿ÀÛ×endstream +endobj +264 0 obj +922 +endobj +265 0 obj<>>>>>endobj +266 0 obj<>stream +xÚ­–Ks›0Çïþ{L3† ñ0ä–&M§3}¤‰{ëE¹¡ÉA"n¾}W\ccw:6Ì>ôÛÕ_BÏ~ø‘ù¦åäí|rq›ñ] +óÚ¢˜˜ÛììK•ñêÍüÚ ÄZ?q#c?r°F¯5œA–W<Õù ‡Œ/rÁèÇæžÕ…–¦\)H¥Ð•,\0Y²(ä*?á…5°Šƒª—KYiž]ÚÒv#¬C#70Pßi4¤‚+“szÃÅë6 cmPñgL+XT²V ^•æ¥jF]ÿò¥ÞN³V&‡"ǰ r¬2scpl£³³!”u¯Ü~‘N/r‘&ç´©æh‘R¯¶Òh±|0cŸÕ±óðïâ(k…jX.9«B嶝â£L™Î¥8Ö¶M5;>µHEVóáªA-yš/r#OÀjÁJ>…wÀ²¬BMO!¸^Éê {Ì4äʨJ®°Í­ìµlƒâÕ ¯.»ñˎËs=寄´†¢­ÄÎÞî3}–‚ﳝ»™,Y.ÜT–û|F¸˜²G¸ !ÜóCÆQ£ðévQ–ã=KwãêKÅ1SÕ)é°lìf–ÖeYÌ<˜‚’(þBçËâD ⶉkõ‡Z¡¤PKº:m™ý¨ËÛUÙªÉ̛ڐ§²ûîÖà]™‡R7 °'þë7÷&SÉÔS«á° ~d6.ß³»³MHâzæAež¾›O<×ÃwÓúçþ=±ë }ì,I"sïaØÀ‡gÞaÏ»yÉuu„(ÎVƒä5DIdy0•ùáñ}ŒÍÓzïð +’Ø != +‚{éŽf:Gs´ÞC$I̸´O‘Ð1$ñ›ßq÷ Å,F]àÈ®ëöHÚÿf#G3´Þƒ alWqÜ# a8ª!=A©÷ ‡[}’h¤…9‚‚¯½ñ"í¼QHlEJƒA”ç ¡'(µó‚Iøt/ ^‡YŒªG£´Î;$Ô6åôsÃÿ<èÄÝ>Kĉf3»€nî¯nçxä»þv÷r¡Wæ¥s••¹ÀS^Å´¬|b¢fÍéÁ±áΌڅßh?À•Øþ®OnØÕ¯“?í9"bendstream +endobj +267 0 obj +841 +endobj +268 0 obj<>>>>>endobj +269 0 obj<>stream +xÚ­–]o›0†ïó+Îe[ +†ð±»´]§JÛÔµ©´‹Þx`V°†Vý÷;Ʀ Iˆ6EDÀyíóØ~±ÏŸ™ þ\ x$åì|9;»ŠÁõlË cAäªÛôè’ñ×ãåo ûàº:hy±¨àrÅ@ÑAš×,iòg²bIžåL…• §%;…ë iZ3)OAÔÀYó"ê'hV´¥E!^X +4IPÀvÅêgVêÓǚ‡céQ¤G*„°ŠB²Z”°(Š-‘-¡;%͹ˆr‹d¿Bx¿ŠsnŸìˆM‰OÕà5MuV–“…¥½v ía©õéݳÓ*¸ì5ƒ¤-˶ êÅ)HøÐäUq˜ë$$”Ã/­D¡}:CõvÊÐqoݪ’ý@Þ)mqüY?È÷Ô\4È,øÀïח·ª§’Ê'cÛ¹iázáÄ8¶¯2êÝÈǗŽzaZ©·Ÿ—3Çvðó}û»ý~d;à»»q€÷ÄÁ[œ¿»1ñý5õ| îö~s|§r:ž8Ð4ؑúí¦ñbõ?•¦WoÐ ƒy8˜×P¸$šÄ†Øz2‡Qržö-rÄdÇ<Ä֓9Œz”Ã÷´Mlې˜ç ^ˆ-'3õ(1G4 óù¤¹pÜګG9¯[ƒ`àì!qx€I{õ‰ˆ6)ñGQ:œ=0ap€S{õ(L@´S=²¯=8óàÃöê õè©9¸Z([Ù­*FkȹÌS†Ûè‡¾Š¤Ûj·öbëÈzqcyf~m³Z¾Vìg¼Í:vʲœã–¯ª”• 2 ØŠñ&×°êªXGOiN‚ÄôCÔ®l‘@á$?æï‹”õÜ–.Sȕh‹T{&ž}GÈFñ°³އy×뱤çTæÉfÖîõ”Ä­Ìùc7!÷߯BE¥ÄK:žÂc-Ú +²¼`²[+KÏÁ?-ÁÿtNÔÒÄG® ðMõr»¸Zâ\ÜßÜÁÈšU°,Ò2ç¹ljڈZÂ7Ê[ڕ›–nn…ÄY¯}üðíwcóAþ˜ý­¦õÞendstream +endobj +270 0 obj +816 +endobj +271 0 obj<>>>>>endobj +272 0 obj<>stream +xÚµVÛrÛ6}×WlõdOMF¤YÎd:ã8v“™8Mkå¡3zIHD  +JÑßwM‰””4ÛcËÀb÷œ³àS/~'0ÓOVö^M{Ïî® Æ)Lç¸7ž$ô1?»®\q#™µçÓÐfI,¢áU<&‹iÁ!l¶›ÇA. ϜXqÈù\(na]0’¯¸=oûyŬÈÚ>X–qkAX0üS…óÁ$ۚ¤„¥ãxDðféø²ƒOiµ)uÕÁÁ{ ÑsåDƜР+l¡+™Ã#‡%7smJžÃì ñ³Jºxv¾… *ŽüÑrÓ z +&Eî*Vr`*‡%ê·Ö&ßeÿ¯`ëxùá.üªÑ˜–•u¨…ÔjNû½¾ÝØ>E¹Œ'  …ÑÕ…r:̘"³‚©§À‚Žw ' þŽ- ~ݒ"Ú ~Hƒ^¸‹:ʲÆÚâLÍâ±½G££¬=Ý»õ;ûÎCfË%g„²"GÂm7ït(ýÓ`öF4L¬t¾<4¾¬Xîl£4Ɏéì˯Ê÷~o{ƒfV|;ªŸ.ëÑÎ8-ê×4T#)ËK¡„u&L¾ 0Ê›ã˜æjO¼Sýێä6KÃ[·U»nŠíµ{s$m”xŽmôÄÒ'éNHw8‡™;~)Ý|üðK£W˜ ‹©¸{=2¢2§ó‰(PGãÿŽú¯ä4 „- Q¦ÕŠçÍ=D†þ„rìQúrÃðô§Å‰³¬vÜÄp !¥(yL‚tz”°2& ã€*\¢^¼šßáDIE”Ìà⊠顇úہL§­ÏÛ©ú;†ûtùg[ßÿý_¥×ªa`c¸%%qÃGÁ=ë˜ÁrY WøEJjùdœÅ-rs-ñ®³W“;¥6»raè…¾àM%):ðϬ\J¼lT¹ãŸÝ³Â•òPV‚WQ''f_Ô篂¬4Åk€5Þħ¢v õ/˜Íö,àéë©ggƒ‹dŽfçð+޷ؽXË´Øùfzÿî·>nì.þòú›éßnq½~¼Ô :÷Ë\œkn­ƒ4`Ùf[SjØúdàíŽÈ9Î=3֏ ŸÔöû¤‚ãO…ÎÀ—Þ°Þq+kƶãÚÖxˆ-½% Ë|•S7½I"ú‚h—KÁB­ tºwGœbÌ"¬¹”Û™lKÒžOÆñs:ÿú¯ë»)¾)üôyÐs·&h×ÍTՈöž©Šù҉Âñè2Ðét@‹£á8¾‚Açí};íýÙû#²v}endstream +endobj +273 0 obj +974 +endobj +274 0 obj<>>>>>endobj +275 0 obj<>stream +xڝWKSã8¾ó+z}Ù ›„$„³'CU3 ÙÓfŠ-Û[òHr2ù÷Ó-%Æ1’)8Äv«ûëî¯úq0„þ átÇóƒËéÁÑ͆C˜Æøer6îŸÁ4êLS±ÐƂ]*ÐeÆ Dœe`TƳ,…MÁ¢d9»ß±È8̹ ØUÁ£>LSaÿKÃã2ƒeÊ¥“TZ$B¢::B*>MŸÐ÷GdEŠù§–-ÙÊ@ÊX¥¬‚¥ÒÏ2!Â7©Ð‘s +,{æ¦aҎœè+Xï*x1¿>ü‚à%£=Šòk&Lª¢w±~ÍžET# înᄌ-¨ ª nW* -† ÷°,Â+r{‡c@YpÝs[¾1åÜÿžux?é7v³à%_A‚µ³ôó°–3,¶¥ªáG,»8³¦8¾ö+][}\k}ì‡øÚŽ£ª-Ð>>>>>endobj +278 0 obj<>stream +xÚUNKnƒ0ÝsŠ·¤Rp€ ʖ~"uQ©mè,<&®°Ú¦\¿8NÕÌêý¿³ +åvmüQgC¶?6¨* rcÚ®a‘¿Hø J*;„3ánøÚ¤íMšK5“ášü—ƒ»iÑdIeȃ#J,qõL&"œ2ÓvËv«òt-IôâC’Kgu¬(QTVÇiQç7‚;e.K`èçùæ%»„ L!“Íÿ,‰fixw^Õ͖Þt¬‰Oýq@ÇÏ·NV†•;B/´2Êǃu¯Ü,|Ž1Er÷uÝuÁ¦îØW@+Ml´æÇGâyÈÞ³_\ãw›endstream +endobj +279 0 obj +257 +endobj +280 0 obj<>>>>>endobj +281 0 obj<>stream +xڅTaoÚ0ýί8åS§‰$ ¾mU«Vê4¦fš¦ušŒcˆWÇf¶Ó*ÿ~w mZJY,…8ðÞó½»Ç߃ƒy“ˆzô©%9°Š5dóIÌ`6ŸBQž|€1,2A:ø(„mLPf󮸃€)0F€qO²yœ¨¨”Qñ-¡Jé…S+é!Tξ-o@Û ¬•–>î‰PùC|JT)²äq§ü½’NB°p¡LÙa¯vA°—ò=fÖ Ë8âu5׺¬“%(ÓQõ éŽá$¹ç.ÍÖ'ˆÞ£?R9)ÞÆðÃ6 ¸¡âÌOG…®Z¥"[ˆú%3žMzS aͺ{*czܗ£wjÓ8”5])Çl¢’¹ÒûßzçÏQ{ö* ûÇ aÐÊ’‹ +.‹b NzÛ8A•óX|GcÑr+g<öݺ®ÙÉÕr B+iB çHD:ÏlÑÊH"Ú5ÆÛ±À~!atfë èºN] 4;¥š›¶C¡{éð8"´wrk]ß +kµ_ÅëDË/7$¼¬•I:ϳ¦)†öMÒZÝÉC¼ö?Þ,M{Þgq&—^Ììq2È«×Ã"5v@i=$μ­p: \-—%è¡1š>Z RÅïå.IåÑè\¢¢áµ¼¶öcs8Ÿ +Ép\üí´=å õ²Ù©½¢»Ù8\5×¼õÛÀ•ñ£]`O‡R²ÙñÓé|ŠÑNéGل^œ£¯£d ¢endstream +endobj +282 0 obj +652 +endobj +283 0 obj<>>>>>endobj +284 0 obj<>stream +xÚ¥VmSã6þίØÉ`JÛ¤¹$ßh7M+f:íÑé(öTl)'ÉäÒ_»VlòäڐIˆ¼oϳ«GúrAHœöø?%‹.D$SzÒëwƒ>$ÙQò€pœüC{ˇG¥Eã—jû#˜JÌ3ً’>•“©p˜›+Q èiõÔà—­“ê¾zÀÕ”~6*ƒ™°v®Mі³Y.1ã”!´£Ó æÂ¦Ú¬†ãÿ}ƒ¯%ÕÊ ©,´Ú­`é÷‚î  2ªµíd¯"c«ª@¶ÜRÁ{ƒ¨æ2}€1 + [݉à1üyûËíÝqåNá$W‹Û  +ᆾ†¼:å5µCÄ?>FñÇ_;Ðkxy9‡77ðCH¯¿Öq´9Æé 轿@÷ ³W±_&É5x;nVFÀZïÏ“Ö ´®oý×ÇþF—wÇoSnÐêÒ¤¯3>•9î˜J_»ïÑÜ'4Vjõ6<;ÃTNypÉ–nídQ™¥4ŠÊpAã÷óíõÍrÁúћË<‘ÏÅÂÂd³¹-Nщ‚hŸy´N¸Òí¦nâ¢Ìx§ ª¸µ¥ÈóHÇ`[qR—&¥Mff‰¼É·Rqª3´ ÂL[+'9zàøU³O F5­Rñ¾×FþKl‰4Ek[uE~Øk?ý´Oß& ‡ûp ÊbB@wåQ§kàšy8ëïõߒmP´™Z³˜©öÕõ5‹… Q±n0EùDÌL.V'Ég@ô# .k/ïӆ4F›¿s}´ÖË wmé°®½ñÜÆD-È%ÓPP“Ä=•ÝTeÓÌʜ ÝùöæÂ(’k[oí½õ)Ç'Ì¡‘Ö:ݚÍڏ+ø‡±Xt¢Á`0ŒèÝÆý¥¤Á=¡3‹ZX‘´1Gh? ;äÝyXÈG< ވGÃ0^ÿÏxñ0î®Ç› ©P)æ¹×•Hû+rÅݳï³J—Ü.{“.]â>µ¥ÙbwqïÝæ˜œoæhÙòc:MKc0 փ®Œÿ®ˆ¿oGd|t¾“ VìT–€Ó0CÃgXÍ'ʲû}É®¶“])ŒR,‘×¼|_ÔÑvÔNÊû{¾µ¬Fl{‚_é㋵^n]/æþRCúK YL Ÿ|3#ߟ‚ŠW֋~sû‘›R.3#˙u·³LñÚýG­854y•IcöøAØÊiŸ¹¤OˆíjR~uåV_ûKß(îÞ^<à„£ßÎ.j]uNß詛óQv–R‘úáHÝ`,…«zéÛï␽ã./žöYäºþgčŸ'Ÿ¾‰AH`endstream +endobj +285 0 obj +1010 +endobj +286 0 obj<>>>>>endobj +287 0 obj<>stream +xڕUQo›@ ~ϯðž–j…I“’·nm¤VªÔ­ìi¦ Éu—»”;†òïks švY"ˆ}öçϟÍó „¿!L#M ]>'ƒ³y á¹I޶ÉtêO ɆɊÆ-ù/©—0’Ÿ$Oè;†0tžÞ(Þ{:cЇíÁî™!ä¤0ÖgéªNvÅ,†+ VƒM!”å…×ä$…âje™P½9äZJ] µ¡r]¬™ZÍZ ±Q6,Ð GtŸ Ʉˆ F6l¢CiðçI/<‘AÆ,÷¬X»š=U®hċ—êà¦ ópÅÍï[n¡ÐÚB?¢àìŽmÏÂ8Žga<‹ÂYpŸüüDâƒ.#|ÍãdÇ£ƒúšF.³.%Š!v×÷m5±î!s¬Í‡›¶º$º3ä 萩dƜ¶56Ú6È¥­„”mî÷SWÌÆKÕäÇ\~8šøã7Ц¾ügÅu+‡t{sßWcÁŸKn,êÅ#GNö0k ±(-¢,§´# +£Ž4lY¥1Yp|ÓNnw^HrÁ¡à†×ãBµâŠÿ©»À{è¿|¿ÀÎd¥‘³¬Àh§`4dZ}´ñ éBSkÑ¡Áár—J ‘þ]ênšŽ¨–|aÊzú°`B¿¯ºA¸'’zÐÐ;zv¦W¬Èp£ˆ”I¢Å„ÉށÙÈ»'&–¦Ü˜·–Û:økÁ¼!ÒÐó¦D'ÌAŒ¦3ˆ5aMÇ(Ô^Dn‰u%äØc¶GšÛóVÛí,§LÒ´NtV¦¼Xë„ LR©ÓC¿ß-&+¶%túÎí¢q £1¢ᆬټúv9OÀƒZÅ:·)ÿ2[ …YÃpÇTÉ$ÅñÜqoo¾ÑÆÓ1¾új{tN\'ƒ¯ƒÑ*Jendstream +endobj +288 0 obj +709 +endobj +289 0 obj<>>>>>endobj +290 0 obj<>stream +xÚ-‹=‚0„÷þŠu¨ÒbPFüèf¢ò:› +Öªãßת¹[î¹<&|"f±UÇÖÄæj!@ „\Ì$–2Փí©PŽÍùP¢ôÍøÒÁ ¨;ÛÛa zôaÀ^÷Oí¦tcü'ó¿-³Ó<ÇwÒÕà®[sq¾…²ÎÄwGìÈÞÛN'pendstream +endobj +291 0 obj +133 +endobj +292 0 obj<>>>/Annots 126 0 R>>endobj +293 0 obj<>stream +xÚÕ[ÛrÛ6¾÷S𲽈BxÀ¥ãԝþÓ´©­>#Ñ[‘t)*¿ýÅ.DÀ ö&bE; | v=qõÏKRý%ODžìÚ«wÛ«··*a*Ù>$,žäE¦?·û¶Õ§CôÉMߍu7ÜþuõÓö*ݤ>|Üý D’‹ROk‘m$‡äx5~xLÞÞf c°$ÌS¸ÜÇ¡~¨v5,2ÍHi†¡ëa›Õÿ±Y9‰Å3ýÙ&Û0"‚’$(­®œç €û—ãX·Éì"n«'ËMæ¯B|ƒõû—zøÒÔÏߺdµ"¡ÇäÊØ¦Ô[.å&'bV® MÆõ½·÷ýîÔêã=/QQK”Z*>ñ /"S®Oû*dʃ×9+ákiêÇÅï‹nsVæz¨Þ ˆó ©¥Yè{íá#—PÞÌ£83Û$SúL{0Ä&œCӍM÷8ç ´‰Êô¥ñàˆMp±+èÌ×[”é¦ðшOh‘“]ü¸ˆðÅË +n,–鋁Ä2ƒ–‚<Íç: ™ VkF‚Ü5ˆ-¬‰)ÚAк މ‹Gü3^¯`;ã”@¥k¸Ë1éӛždˆeÌòt¡R—¥¥„Œ|ªwŸ»þÐ?¾|[ŒÓæsM¾]FÄ)3ã ôs"‚â”9:†ÿõŸŽß–SënbB\K£Mru&‚Bѝ‰@nÕñX碾K%&­T0ÿ¹±'† +„§è n›ÃX3ѱG¶êƒJš»›—à JZ8f½æí‘öˆ½†'>Á½š/³2éÊ̑þËÂb•JC\–úx «Tæ¤ýVÏýð·ö–3vy5¡êRa@à*óÜ"ˆ#ñû¢ÀUæ$\-¼‰/=|äJ,pµ09Üz†Ø„óîÔöÁxÆAЛNµÛõàˆMpU·loš iÎW$>AýÒÇêp>› ¢!³â¬»YîIíæÏ÷3†ï¢W²ˆ\¿L`®”‚ê ±,–™D£¿D˜º^ +’Po)b`À™¦‚š(ÀB>Ý÷§aW‡T<À­€iœ@xï›ã84ŸNcÓw³fç2n^Ë:?ÐZÖyæ B{t¤fÕ\è-K†Þæ®þçÔ ukKh_o9O×ÿÅ$À Œ÷9? +J€›¸÷¦oŸš˜¡˜!c†xØÃ·ʘ™¸tیˆ ¬"±¶h¨ ™Ääa‘¹u@áœrˆÜ%ìÂCž;.6> °ûþa|®†¹úmy©X"¦4EçÄ eA*¨”¡¯º;u]D"úÓÒÇ·0¬ gºËM çÑ‹hC],²SaW*´÷9»R$B‘¬(Ëé@Ï €—ó v¹ÌZÆA >ò è]ÓUÃKH³Ü3¸aœPþ z#¨‚¹È&)Nßæ"7NT„Ãr n¢g¹|IPnAt¬òꉽ,u¦›s–ùXÄ6XœêSÁé¨Õ™×\}_ºlìUÆíƒ!4Ê"C't½§®žÖ $ª8±³©«3õÁ}(âԇ~ß<¼„·ƒaÓÑ H2 +ÇU½½èÕÄ>BՒêe– +Å>‚sôAÃÂsð@àñ•W®¿ ki+`‘7g\a…)#(WùòjµÅÆjµNü/HVW«ŽJ´Ä6Š\éC€DP¢%uUÜ×cø½®¨/@¾a>:±ù‚ÌיŒµŽWJ|Û>R?T§Ã®mLOÆ2øßóNÏLC]TáQíæ%F +ðv‰ vsEéêX aõ:ˆ:V€b„Olµ$V˜&C‘"5Šøç'럞ÂÞ΁ÀÔ\ù€v€Zq¨°@µ5É3TmFÝ-×»]ý4Ɯ˄ÏR¨Šx ”r‚ ªÖ ¤G’@`wõ_õnŒ‚ÄÆV{4Àí4 +E€†S”ùp4€à=åw>(LÓ{ÎÕ9½Çï‹Ò{.Ìd8½·à&÷Ð 1bé½1½\²ea«˜3­\²lQ£ØysYñZvÈG¬ þåzXä 5gØ3SÂC"±,»çŒºgn>WÝc،LØZ/\#w!bç "g2Xtã\(âÛ'뻇æñ4TP’ œAG£–Æc¹¨vÁÞ6‡z¾_è»GQ §ØT»\$‚þ!¥ mÝ>õC°Dê@‚PçÕ¦2˜–Ûªš#"e%¶`‰”)j!¢ÆŽ@05B¤ÎkÙhÊð-œw¾g_`^¼/‰åáj+°;HA‰P±ƒ¶÷¨f,.Ëר •CŽÍBJi!”CnÁ¯ödÝlWÚÊ䕁T”ÝA-© ²ò»¡>ÖóGBªµˆ"*A]9N¤‚"¶%Ɉàz¿êã\?CyqsÀ"=; yi+;Hm+— k‹ 8+í=xâÛöšzwšq¦3Z@¥aE‹ED£¿1B*x¦µÈüÚïÞE”kjŽ Aa‹‰U¬EFáO††ýlÁG®®ã—EZ*Jl1þ¥Œ5¸”Ô>r}8ôÏÿ÷‘@m +‚û"ÖQRPËÆûº›1¦÷ieqSadÔÏÀÀ¯dEäÍRFÍ ×§ñóöåi¦mE +}¥V"‡Øþ¥$Ko… ì*¢ŸÜÂþMÁV«9<¼\´]  ZÁ"vPœ·ÿóПž~«Ú™3P\öW¸ë··%U(ޘ»™—ø*àîúv›¼I ?1±XÉ5´@ÓN5öÃ1ùPu§ê(Âôf¿)¸ÙPCâüãêÿ“b~›endstream +endobj +294 0 obj +2304 +endobj +295 0 obj<>>>/Annots 151 0 R>>endobj +296 0 obj<>stream +xÚ͖MÚ0†ïü +Û^ÄNr¤Û²—VÚ.YõX¥!@*’Ð$´ÚߙØCà EXö<¶ßמɯ ' ¾œH¿¬œ|H&ó˜ð˜$+µ¤‚èPÁ3Y¾KÒۜÔ+òXW]^uíûäçäS2a”/O$”-#ˆ+ —‚*ÛڒNqѬÉÃ< œã¤!Ì(c3ãâ­íòò©©÷;œëÆl˜f0áPzÏ`£JHJϒ(EcÛlÐBãŽæ¨= +vX%‰ù9ØvPݔ©që_¥¢üö +^/¨9ZœÓ–‡Ö¨¢x ¸€°Ç²(sÚ½íò5‚˜ÊûPã’*ލî%Pp»LË'Šcªduõ{D%îBÁG÷Ïpû &L*æ¿'µ(›Z0LšÌ¢ÆoÖ ê†pNø¦×R¦ã'.~p¾LÛm9ÏMµñÜöÀ]‹ + ×=p—5˲z_uEµ±XÞË)7VKúT*Ž U™Æu©Òý&¿mòƓIlI˜§s˜nCêêqŒ‰ ô×å˜~ÙÕÒstœ`@ñ/¸‹²ìš6ž½¹ÁX‰ãƒœÊ 0¨Ïõڃr‚•÷L(pÜßv,à +™øFgïâA T_Vúâi¾:­mªJ²¹T¨2gsѶߢÒ,ËÛöûÖë„1508E,Ýø¿\ÝI±»d ¼Bêƒ1}ÃkŒ”¦Ö]aŒ%CuT§dÛmIyÓԍ߁·VÓðhû-ÐcЦâ^²³.Ã1« Æô ¯1³ÆuÆX2¼Øœ‘M÷@Ú¥ëü‚/‘ƒC_Ø)Ïô<¯/ÑÝø¢póÈ»χ7¼/³yB¦äñõyAõªû“Bý›-Ë¢*Ú®I»ºiɗ´Ú§[¤L¹À·‡i(úÍ…Uòëä/ +KáŠendstream +endobj +297 0 obj +714 +endobj +298 0 obj<>endobj +299 0 obj<>endobj +300 0 obj<>endobj +301 0 obj<>endobj +302 0 obj<>endobj +303 0 obj<>endobj +304 0 obj<>endobj +305 0 obj<>endobj +306 0 obj<>endobj +307 0 obj<>endobj +308 0 obj<>endobj +309 0 obj<>endobj +310 0 obj<>endobj +311 0 obj<>endobj +312 0 obj<>endobj +313 0 obj<>endobj +314 0 obj<>endobj +315 0 obj<>endobj +316 0 obj<>endobj +317 0 obj<>endobj +318 0 obj<>endobj +319 0 obj<>endobj +320 0 obj<>endobj +321 0 obj<>endobj +322 0 obj<>endobj +323 0 obj<>endobj +324 0 obj<>endobj +325 0 obj<>endobj +326 0 obj<>endobj +327 0 obj<>endobj +328 0 obj<>endobj +329 0 obj<>endobj +330 0 obj<>endobj +331 0 obj<>endobj +332 0 obj<>endobj +333 0 obj<>endobj +334 0 obj<>endobj +335 0 obj<>endobj +336 0 obj<>endobj +337 0 obj<>endobj +338 0 obj<>endobj +339 0 obj<>endobj +340 0 obj<>endobj +341 0 obj<>endobj +342 0 obj<>endobj +343 0 obj<>endobj +344 0 obj<>endobj +345 0 obj<>endobj +346 0 obj<>endobj +347 0 obj<>endobj +348 0 obj<>endobj +349 0 obj<>endobj +350 0 obj<>endobj +351 0 obj<>endobj +352 0 obj<>/Outlines 298 0 R/PageMode/UseOutlines/OpenAction[214 0 R/XYZ null null null]>>endobj +xref +0 353 +0000000000 65535 f +0000000015 00000 n +0000000227 00000 n +0000000288 00000 n +0000000362 00000 n +0000000444 00000 n +0000000522 00000 n +0000000599 00000 n +0000000678 00000 n +0000000754 00000 n +0000000835 00000 n +0000000894 00000 n +0000000999 00000 n +0000001104 00000 n +0000001209 00000 n +0000001314 00000 n +0000001379 00000 n +0000001464 00000 n +0000001516 00000 n +0000001574 00000 n +0000001658 00000 n +0000001718 00000 n +0000001802 00000 n +0000001833 00000 n +0000001937 00000 n +0000002042 00000 n +0000002147 00000 n +0000002252 00000 n +0000002357 00000 n +0000002460 00000 n +0000002563 00000 n +0000002667 00000 n +0000002772 00000 n +0000002877 00000 n +0000002982 00000 n +0000003087 00000 n +0000003192 00000 n +0000003297 00000 n +0000003402 00000 n +0000003507 00000 n +0000003612 00000 n +0000003717 00000 n +0000003822 00000 n +0000003927 00000 n +0000004032 00000 n +0000004135 00000 n +0000004238 00000 n +0000004342 00000 n +0000004447 00000 n +0000004552 00000 n +0000004657 00000 n +0000004762 00000 n +0000004867 00000 n +0000004972 00000 n +0000005077 00000 n +0000005182 00000 n +0000005287 00000 n +0000005392 00000 n +0000005497 00000 n +0000005602 00000 n +0000005707 00000 n +0000005812 00000 n +0000005917 00000 n +0000006022 00000 n +0000006127 00000 n +0000006232 00000 n +0000006337 00000 n +0000006442 00000 n +0000006545 00000 n +0000006648 00000 n +0000006752 00000 n +0000006857 00000 n +0000006962 00000 n +0000007067 00000 n +0000007172 00000 n +0000007277 00000 n +0000007382 00000 n +0000007487 00000 n +0000007592 00000 n +0000007697 00000 n +0000007802 00000 n +0000007907 00000 n +0000008012 00000 n +0000008117 00000 n +0000008222 00000 n +0000008327 00000 n +0000008432 00000 n +0000008537 00000 n +0000008642 00000 n +0000008747 00000 n +0000008852 00000 n +0000008957 00000 n +0000009062 00000 n +0000009167 00000 n +0000009272 00000 n +0000009377 00000 n +0000009482 00000 n +0000009587 00000 n +0000009692 00000 n +0000009797 00000 n +0000009902 00000 n +0000010006 00000 n +0000010110 00000 n +0000010215 00000 n +0000010321 00000 n +0000010427 00000 n +0000010533 00000 n +0000010639 00000 n +0000010745 00000 n +0000010851 00000 n +0000010957 00000 n +0000011063 00000 n +0000011169 00000 n +0000011275 00000 n +0000011381 00000 n +0000011487 00000 n +0000011593 00000 n +0000011699 00000 n +0000011805 00000 n +0000011911 00000 n +0000012017 00000 n +0000012123 00000 n +0000012229 00000 n +0000012335 00000 n +0000012440 00000 n +0000012544 00000 n +0000012648 00000 n +0000013413 00000 n +0000013519 00000 n +0000013623 00000 n +0000013728 00000 n +0000013834 00000 n +0000013940 00000 n +0000014044 00000 n +0000014148 00000 n +0000014252 00000 n +0000014357 00000 n +0000014462 00000 n +0000014568 00000 n +0000014674 00000 n +0000014780 00000 n +0000014886 00000 n +0000014992 00000 n +0000015096 00000 n +0000015201 00000 n +0000015307 00000 n +0000015411 00000 n +0000015516 00000 n +0000015622 00000 n +0000015726 00000 n +0000015831 00000 n +0000015937 00000 n +0000016147 00000 n +0000016181 00000 n +0000016215 00000 n +0000016916 00000 n +0000016965 00000 n +0000017014 00000 n +0000017063 00000 n +0000017112 00000 n +0000017161 00000 n +0000017210 00000 n +0000017259 00000 n +0000017308 00000 n +0000017357 00000 n +0000017406 00000 n +0000017455 00000 n +0000017504 00000 n +0000017553 00000 n +0000017602 00000 n +0000017651 00000 n +0000017700 00000 n +0000017749 00000 n +0000017798 00000 n +0000017847 00000 n +0000017896 00000 n +0000017945 00000 n +0000017994 00000 n +0000018043 00000 n +0000018092 00000 n +0000018141 00000 n +0000018190 00000 n +0000018239 00000 n +0000018288 00000 n +0000018337 00000 n +0000018386 00000 n +0000018435 00000 n +0000018484 00000 n +0000018533 00000 n +0000018582 00000 n +0000018631 00000 n +0000018680 00000 n +0000018729 00000 n +0000018778 00000 n +0000018827 00000 n +0000018876 00000 n +0000018925 00000 n +0000018974 00000 n +0000019023 00000 n +0000019072 00000 n +0000019121 00000 n +0000019170 00000 n +0000019219 00000 n +0000019268 00000 n +0000019317 00000 n +0000019366 00000 n +0000019415 00000 n +0000019464 00000 n +0000019773 00000 n +0000019925 00000 n +0000026317 00000 n +0000026339 00000 n +0000026452 00000 n +0000026554 00000 n +0000026574 00000 n +0000026705 00000 n +0000027474 00000 n +0000027495 00000 n +0000027636 00000 n +0000028014 00000 n +0000028035 00000 n +0000028175 00000 n +0000029089 00000 n +0000029110 00000 n +0000029250 00000 n +0000030693 00000 n +0000030715 00000 n +0000030855 00000 n +0000031753 00000 n +0000031774 00000 n +0000031887 00000 n +0000032089 00000 n +0000032110 00000 n +0000032264 00000 n +0000033166 00000 n +0000033187 00000 n +0000033341 00000 n +0000034270 00000 n +0000034291 00000 n +0000034440 00000 n +0000035151 00000 n +0000035172 00000 n +0000035285 00000 n +0000035488 00000 n +0000035509 00000 n +0000035667 00000 n +0000036420 00000 n +0000036441 00000 n +0000036599 00000 n +0000037553 00000 n +0000037574 00000 n +0000037732 00000 n +0000038718 00000 n +0000038739 00000 n +0000038888 00000 n +0000039611 00000 n +0000039632 00000 n +0000039772 00000 n +0000040430 00000 n +0000040451 00000 n +0000040600 00000 n +0000041626 00000 n +0000041647 00000 n +0000041806 00000 n +0000042799 00000 n +0000042820 00000 n +0000042988 00000 n +0000043900 00000 n +0000043921 00000 n +0000044080 00000 n +0000044967 00000 n +0000044988 00000 n +0000045138 00000 n +0000046183 00000 n +0000046204 00000 n +0000046363 00000 n +0000047816 00000 n +0000047838 00000 n +0000047969 00000 n +0000048297 00000 n +0000048318 00000 n +0000048467 00000 n +0000049190 00000 n +0000049211 00000 n +0000049370 00000 n +0000050451 00000 n +0000050473 00000 n +0000050622 00000 n +0000051402 00000 n +0000051423 00000 n +0000051536 00000 n +0000051740 00000 n +0000051761 00000 n +0000051916 00000 n +0000054291 00000 n +0000054313 00000 n +0000054468 00000 n +0000055253 00000 n +0000055274 00000 n +0000055329 00000 n +0000055434 00000 n +0000055578 00000 n +0000055681 00000 n +0000055786 00000 n +0000055951 00000 n +0000056059 00000 n +0000056174 00000 n +0000056279 00000 n +0000056387 00000 n +0000056495 00000 n +0000056611 00000 n +0000056709 00000 n +0000056878 00000 n +0000057034 00000 n +0000057134 00000 n +0000057249 00000 n +0000057373 00000 n +0000057481 00000 n +0000057601 00000 n +0000057766 00000 n +0000057873 00000 n +0000058039 00000 n +0000058144 00000 n +0000058262 00000 n +0000058378 00000 n +0000058506 00000 n +0000058637 00000 n +0000058759 00000 n +0000058926 00000 n +0000059046 00000 n +0000059162 00000 n +0000059320 00000 n +0000059412 00000 n +0000059519 00000 n +0000059630 00000 n +0000059731 00000 n +0000059884 00000 n +0000059980 00000 n +0000060086 00000 n +0000060192 00000 n +0000060297 00000 n +0000060406 00000 n +0000060516 00000 n +0000060630 00000 n +0000060729 00000 n +0000060865 00000 n +0000060963 00000 n +0000061061 00000 n +0000061207 00000 n +0000061322 00000 n +0000061442 00000 n +0000061561 00000 n +0000061666 00000 n +trailer +<> +startxref +61852 +%%EOF diff --git a/doc/sam.shtml b/doc/sam.shtml new file mode 100644 index 0000000000..bffb8c2a8a --- /dev/null +++ b/doc/sam.shtml @@ -0,0 +1,1038 @@ + + + + + + DRAFT - CUPS Software Administrators Manual + + + +

Preface

+ +This software administrators manual provides printer administration +information for the Common UNIX Printing System ("CUPS") Version 1.0.0. + +

System Overview

+ +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +

This software administrators manual is organized into the following sections:

+ +
    +
  • 1 - Printing System Overview
  • +
  • 2 - Building and Installing CUPS
  • +
  • 3 - Printer Queue Management
  • +
  • 4 - Printing System Management
  • +
  • 5 - Printer Accounting
  • +
+ +

1 - Printing System Overview

+ +

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 MacOS, UNIX has no standard interface or +system in place for supporting printers. Among the solutions previously +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 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. + +

The Common UNIX Printing System, or 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, or IPP. IPP has been embraced by dozens of printer +and printer server manufacturers, and will be supported by the next +Microsoft Windows operating system. + +

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 secure printing solution than older ones. + +

IPP is layered on top of the Hyper-Text Transport Protocol, or HTTP, +which is the basis of web servers on the Internet. This allows the user to +view documentation and status information on a printer or server using their +web browser. + +

CUPS provides a complete IPP/1.0-based printing system that provides Basic +authentication and domain or IP-based access control. Digest authentication +and TLS encryption will be available in future versions of CUPS. + +

Jobs

+ +

Each file 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. + +

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. Backend filters perform the most +important task of all - they send the filtered print data to the +printer. + +

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 Processors, or RIPs, that +convert PostScript or image files into bitmaps that can be sent to a +raster printer. + +

CUPS provides backends for printing over parallel and serial ports, +and over the network via the JetDirect (AppSocket), Server Message +Block, and Line Printer Daemon protocols. + +

Printer Drivers

+ +

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes a sample printer driver for Hewlett-Packard +LaserJet and DeskJet printers. While this driver does not generate +optimal output for different printer models, it does 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. If there is only one occurrence of a printer on a network, +then that printer can be accessed using its name alone. If more than one +printer exists with the same name, users must select the printer by specifying +which server to use (e.g. "printer@host1" or "printer@host2".) + +

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 +goes down! + +

2 - Building and Installing CUPS

+ +

This chapter shows how to build and install the Common UNIX Printing System. +If you are installing a binary distribution from the CUPS web site, proceed to +the section titled, Installing a Binary Distribution. + +

Installing a Source Distribution

+ +

Requirements

+ +

You'll need an ANSI C compiler to build CUPS on your system. As its name +implies, CUPS is designed to run on the UNIX operating system, however +the CUPS interface library and most of the filters and backends supplied +with CUPS should also run under Microsoft® Windows®. + +

For the image file filters and PostScript RIP, you'll need the JPEG, +PNG, TIFF, and ZLIB libraries. CUPS will build without these, but with +reduced functionality. Easy Software Products maintains a mirror of the +current versions of these libraries at: + +

+ +

If you make changes to the man pages you'll need GNU groff or another +nroff-like package. GNU groff is available from: + +

+ +

The documentation is formatted using the HTMLDOC software. If you need to +make changes you can get the HTMLDOC software from: + +

+ +

Compiling CUPS

+ +

CUPS uses GNU autoconf to configure the makefiles and source code +for your system. To configure CUPS for your system type: + +

    +% ./configure ENTER
    +
+ +

The default installation will put the CUPS software in the +/usr and /var directories on your system, +which will overwrite any existing printing commands on your system. To +install the CUPS software in another location use the +--prefix option: + +

    +% ./configure --prefix=/usr/local ENTER
    +
+ +

If the PNG, JPEG, TIFF, and ZLIB libraries are not installed in a +system default location (typically /usr/include and +/usr/lib) you'll need to set the CFLAGS and +LDFLAGS environment variables prior to running configure: + +

    +% setenv CFLAGS "-I/some/directory"
    +% setenv LDFLAGS "-L/some/directory"
    +% ./configure ... ENTER
    +
+ +

Once you have configured things, just type: + +

    +% make ENTER
    +
+ +

to build the software. + +

Installing the Software

+ +

To install the software type: + +

    +% make install ENTER
    +
+ +

Running the Software

+ +Once you have installed the software you can start the CUPS daemon by +typing: + +
    +% /usr/sbin/cupsd & ENTER
    +
+ +

Installing a Binary Distribution

+ +

We are currently distributing CUPS binary distributions in TAR format +with installation and removal scripts. + +

    + WARNING: + +

    Installing CUPS will overwrite your existing printing + system. If you experience difficulties with the CUPS software + and need to go back to your old printing system, you will need + to remove the CUPS software with the provided script and + reinstall the printing system from your operating system CDs. +

+ +

To install the CUPS software you will need to be logged in as root +(doing an "su" is good enough). Once you are the root user, run the +installation script with: + +

    +./cups.install ENTER
    +
+ +

After asking you a few yes/no questions the CUPS software will be +installed and the scheduler will be started automatically. + +

3 - Printer Queue Management

+ +

This chapter discusses how to add, modify, and delete print queues +on your system. + +

The lpadmin Command

+ +

The lpadmin command allows you to perform most printer +administration tasks from the command-line. Since lpadmin +is also a System V printing system command, it is located in the +/usr/lib directory instead of a more common one like +/usr/bin or /usr/sbin. + +

Adding and Modifying Printers

+ +

To add a printer to CUPS you simply run the lpadmin command +with the "-p" option: + +

    +% /usr/lib/lpadmin -pprinter -E -vdevice -Pppd ENTER
    +
+ +

Spaces between the option letter and value are optional. + +

The printer name can be up to 127 letters, digits, hyphens, +and underscores. Unlike other printing systems, the printer name in +CUPS is not case-sensitive, so you can't add two printers named +LaserJet and laserjet. + +

The device argument specifies the device URI or filename for the +printer. The following devices are supported in a basic installation of +CUPS: + +

+ +
file:/dev/filename +
/dev/filename +
Sends all output to the specified file. + +
http://[username:password@]hostname[:port]/resource +
ipp://[username:password@]hostname[:port]/resource +
Sends all output to the specified IPP printer or server. + The port parameters defaults to 631. + +
lpd://hostname/queue +
Sends all output to the specified LPD printer queue. + +
parallel:/dev/filename +
Sends all output to the specified parallel port device. + +
serial:/dev/filename[?options] +
Sends all output to the specified serial port device. The + options can be any of the following separated by the + plus (+) character: +
    +
  • baud=rate - Sets the baud rate + for the device. +
  • bits=7 or 8 - Sets the number + of data bits. +
  • parity=even - Sets even parity + checking. +
  • parity=odd - Sets odd parity + checking. +
  • parity=none - Turns parity + checking off. +
+ +
smb://[username:password@]hostname/queue +
Sends all output to the specified SMB (Windows) printer queue + using the SAMBA software. + +
socket://hostname[:port] +
Sends all output to the specified printer using the + AppSocket protocol. The port parameter defaults to 9100. + +
+ +

The ppd argument specifies the PostScript Printer Description file +to use for this printer. Many options (such as media size, etc.) will not +be available if you omit this part of the lpadmin command. + +

Using Standard Printer Drivers

+ +

The lpadmin command allows you to use "standard" PPD files +and interface scripts located in the /usr/share/cups/model +directory with the "-m" option: + +

    +% /usr/lib/lpadmin -pprinter -E -vdevice -mmodel ENTER
    +
+ +

The model argument specifies the name of the PPD file or interface +script. For example, to add a printer using the sample HP DeskJet series +driver connected to parallel port 1 under Linux you would use: + +

    +% /usr/lib/lpadmin -pDeskJet -E -vparallel:/dev/par1 -mdeskjet.ppd ENTER
    +
+ +

Removing Printers

+ +

To remove a printer to CUPS you simply run the lpadmin command +with the "-x" option: + +

    +% /usr/lib/lpadmin -xprinter ENTER
    +
+ +

Printer Classes

+ +

CUPS allows you to group similar printers in a printer class. When +a user sends a print job to a class, the job will be processed by the first +available printer in that class. + +

To add a printer to a class you simply run the lpadmin command +with the "-p" and "-c" options: + +

    +% /usr/lib/lpadmin -pprinter -cclass ENTER
    +
+ +

The class is created automatically if it doesn't exist. To remove a +class just use the "-x" option: + +

    +% /usr/lib/lpadmin -xclass ENTER
    +
+ +

Setting the Default Printer

+ +

To set the default printer or class simply run the lpadmin +command with the "-d" option: + +

    +% /usr/lib/lpadmin -ddestination ENTER
    +
+ +

The destination argument is the name of the printer or class. + +

Starting and Stopping Printers

+ +

The enable and disable commands start and stop +printer queues, respectively: + +

    +% /usr/bin/enable printer ENTER
    +% /usr/bin/disable printer ENTER
    +
+ +

Printers that are disabled may still accept jobs for printing, but won't +actually print any files until they are restarted. This is useful if the +printer malfunctions and you need time to correct the problem. Any queues +jobs are printed after the printer is enabled (started). + +

Accepting and Rejecting Print Jobs

+ +

The accept and reject commands accept and reject +print jobs for the named printer, respectively: + +

    +% /usr/lib/accept printer ENTER
    +% /usr/lib/reject printer ENTER
    +
+ +

As noted above, a printer can be stopped but accepting new print +jobs. A printer can also be rejecting new print jobs while it finishes +those that have been queued. This is useful for when you must perform +maintenance on the printer and will not have it available to users for +a long period of time. + +

4 - Printing System Management

+ +

This chapter shows how you can configure the CUPS server. + +

Changing the Configuration Files

+ +

All of the server configuration files are located in the +/var/cups/conf directory. Once you have made a change to a +file you need to restart the CUPS server by sending it a HUP signal or +using the supplied script "cups.sh": + +

    +% ./cups.sh restart ENTER
    +
+ +

The binary distribution installs the script in the +init.d directory with the name lp or +lpd depending on the vendor-supplied printing system. + +

Temporary Files

+ +

Normally CUPS puts all of its temporary files in /var/tmp. +If you'd like to change this directory you'll need to edit the +/var/cups/conf/cupsd.conf file. + +

Start by creating the new temporary directory and setting the appropriate +permissions: + +

    +% mkdir /foo/bar/tmp ENTER
    +% chmod a+rwxt /foo/bar/tmp ENTER
    +
+ +

Then change the line containing the TempDir directive in +the cupsd.conf to the directory that you've created: + +

    +TempDir /foo/bar/tmp
    +
+ +

Finally, restart the server as outlined in the first section of this +chapter. + +

Network Configuration

+ +

The default configuration of the CUPS server listens for connections from +all network interfaces on port 631 (the standard IPP port). Administration +functions are limited to local connections with the appropriate username and +password. + +

If you'd like to limit access to your system you'll need to edit the +/var/cups/conf/cupsd.conf file. + +

Port

+ +

The Port directive specifies a port to listen on for +all interfaces. Besides the standard IPP port (631) you can also setup +your server to listen on the HTTP port (80) to use your CUPS server as +a standard web server as well. + +

Listen

+ +

The Listen directive specifies a listening address and port, +extending the functionality of the Port directive. If you want +to allow connections only from the local machine you can use: + +

    +Listen 127.0.0.1:631
    +
+ +

instead of the Port directive. + +

If you want to limit access to a specific network/subnet, make sure you +specify only the network address and not your system's network address! + +

BrowsePort

+ +

The BrowsePort directive controls which port is monitored for +remote printers. By default it is set to the IPP port (631), however you can +change it as needed. + +

    + + NOTE: + +

    You must set the BrowsePort to the same value + on all of the systems that you want to see. + +

+ +

BrowseAddress

+ +

The BrowseAddress directive specifies a broadcast address to +use when sending printer status updates over the network. The default +browse address is 255.255.255.255 which will send printer +information to all subnets. + +

    + + NOTE: + +

    If you are using HP-UX 10.20 and a subnet that is not 24, + 16, or 8 bits, printer browsing (and in fact all broadcast + reception) will not work. This problem appears to be fixed in + HP-UX 11.0. + +

+ +

Printer Security

+ +

CUPS provides IP and domain-name based access control and Basic +authentication for authentication. + +

Location

+ +

The Location directive defines access control for a +specific HTTP directory. The following pseudo directories are provided +by the CUPS server: + +

    + +
  • /admin - This is the URI that must be referenced to + do printer administation commands. + +
  • /classes - This is the URI that must be referenced to + access printer classes. + +
  • /jobs - This is the URI that must be referenced to + access jobs. + +
  • /printers - This is the URI that must be referenced to + access printers. + +
+ +

All other directories are taken from the +/usr/share/cups/doc directory. + +

The Location directive surrounds the other access control +directives described below. The default server configuration uses: + +

    +<Location /admin>
    +AuthType Basic
    +AuthClass System
    +
    +Order Deny,Allow
    +Deny From All
    +Allow From 127.0.0.1
    +</Location>
    +
+ +

Order

+ +

The Order directive defines the default access control. +The following values are supported: + +

    + +
  • Order Allow,Deny - Allow requests from all + systems except for those listed in a Deny + directive. + +
  • Order Deny,Allow - Allow requests only from + those listed in an Allow directive. + +
+ +

The Order directive must appear inside a +Location directive. + +

Allow

+ +

The Allow directive specifies a hostname, IP address, or +network that is allowed access to the server: + +

    +Allow from All
    +Allow from None
    +Allow from *.domain.com
    +Allow from .domain.com
    +Allow from host.domain.com
    +Allow from nnn.*
    +Allow from nnn.nnn.*
    +Allow from nnn.nnn.nnn.*
    +Allow from nnn.nnn.nnn.nnn
    +Allow from nnn.nnn.nnn.nnn/mm
    +Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
+ +

Allow directives are cummulative, so multiple Allow +directives can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mmnetmask
00.0.0.0
1128.0.0.0
2192.0.0.0
......
8255.0.0.0
16255.255.0.0
24255.255.255.0
32255.255.255.255
+ +

The Allow directive must appear inside a +Location directive. + +

Deny

+ +

The Deny directive specifies a hostname, IP address, or +network that is allowed access to the server: + +

    +Deny from All
    +Deny from None
    +Deny from *.domain.com
    +Deny from .domain.com
    +Deny from host.domain.com
    +Deny from nnn.*
    +Deny from nnn.nnn.*
    +Deny from nnn.nnn.nnn.*
    +Deny from nnn.nnn.nnn.nnn
    +Deny from nnn.nnn.nnn.nnn/mm
    +Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +
+ +

Deny directives are cummulative, so multiple Deny +directives can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
mmnetmask
00.0.0.0
1128.0.0.0
2192.0.0.0
......
8255.0.0.0
16255.255.0.0
24255.255.255.0
32255.255.255.255
+ +

The Deny directive must appear inside a +Location directive. + +

AuthType

+ +

The AuthType directive defines the type of authentication to +perform: + +

    + +
  • None - No authentication should be performed + (default.) + +
  • Basic - Basic authentication should be + performed using the UNIX password and group files. + +
+ +

The AuthType directive must appear inside a +Location directive. + +

AuthClass

+ +

The AuthClass directive defines what level of Basic +access is required: + +

    + +
  • Anonymous - No authentication should be performed + (default.) + +
  • User - A valid username and password is required. + +
  • System - A valid username and password is + required, and the username must belong to the "sys" group (this + can be changed using the SystemGroup directive, + below. + +
  • Group - A valid username and password is + required, and the username must belong to the group named by + the AuthGroupName directive. + +
+ +

The AuthClass directive must appear inside a +Location directive. + +

AuthGroupName

+ +

The AuthGroupName directive sets the group to use for +Group authentication. + +

The AuthGroupName directive must appear inside a +Location directive. + +

SystemGroup

+ +

The SystemGroup directive sets the administration group used +when authenticating the System type. It defaults to the "sys" +group. + +

File Formats

+ +

CUPS provides a MIME-based file typing and filtering mechanism to +convert files to a printable format for each printer. The +mime.types and mime.convs files define the +file type and filters that are available on the system. + +

mime.types

+ +

The mime.types defines the known file types. Each line +of the file starts with the MIME type and may be followed by one or +more file type recognition rules. For example, the +text/html file type is defined as: + +

    +text/html html htm \
    +          printable(0,1024) + (string(0,"<HTML>") string(0,"<!DOCTYPE"))
    +
+ +

The first two rules say that any file with an extension of ".html" or +".htm" is a HTML file. The third rules says that any file whose first +1024 characters are printable text and starts with the strings "<HTML>" +or "<!DOCTYPE" is a HTML file as well. + +

The first two rules deal solely with the name of the file being +typed. This is useful when the original filename is known, however for +print files the server doesn't always have a filename to work with. The +third rule takes care of this possibility and automatically figures out +the file type based upon the contents of the file instead. + +

The available tests are: + +

    + +
  • ( expr ) - Parenthesis for expression grouping + +
  • + - Logical AND + +
  • , or whitespace - Logical OR + +
  • ! - Logical NOT + +
  • match("pattern") - Pattern match on filename + +
  • extension - Pattern match on "*.extension" + +
  • ascii(offset,length) - True if bytes are valid + printable ASCII (CR, NL, TAB, BS, 32-126) + +
  • printable(offset,length) - True if bytes are + printable 8-bit chars (CR, NL, TAB, BS, 32-126, 160-254) + +
  • string(offset,"string") - True if bytes are + identical to string + +
  • char(offset,value) - True if byte is identical + +
  • short(offset,value) - True if 16-bit integer + is identical (network or "big-endian" byte order) + +
  • int(offset,value) - True if 32-bit integer is + identical (network or "big-endian" byte order) + +
  • locale("string") - True if current locale + matches string + +
+ +

mime.convs

+ +

The mime.convs file defines all of the filter programs that +are known to the system. Each line consists of: + +

    +source destination cost program
    +
    +text/plain application/postscript 50 texttops
    +application/vnd.cups-postscript application/vnd.cups-raster 50 pstoraster
    +image/* application/vnd.cups-postscript 50 imagetops
    +image/* application/vnd.cups-raster 50 imagetoraster
    +
+ +

The source field is a MIME type, optionally using a wildcard for +the super-type or sub-type (e.g. "text/plain", "image/*", "*/postscript"). + +

The destination field is a MIME type defined in the +mime.types file. + +

The cost field defines a relative cost for the filtering +operation from 1 to 100. The cost is used to choose between two +different sets of filters when converting a file. For example, to convert +from image/jpeg to application/vnd.cups-raster, +you could use the imagetops and pstoraster +filters for a total cost of 100, or the imagetoraster filter +for a total cost of 50. + +

The program field defines the filter program to run; the +special program "-" can be used to make two file types equivalent. The +program must accept the standard filter arguments and environment +variables described in the CUPS Interface Design Document: + +

    +program job user title options [filename]
    +
+ +

If specified, the filename argument defines a file to read +when filtering, otherwise the filter must read from the standard input. +All filtered output must go to the standard output. + +

5 - Printer Accounting

+ +This chapter describes the CUPS log files. + +

Where to Find the Log Files

+ +

The log files are normally stored in the /var/cups/logs +directory. You can change this by editing the +/var/cups/conf/cupsd.conf configuration file. + +

The access_log File

+ +

The access_log file lists each HTTP resource that is accessed +by a web browser or CUPS/IPP client. Each line is in the so-called "Common +Log Format" used by many web servers and web reporting tools: + +

    +host group user date-time \"method resource version\" status bytes
    +
    +127.0.0.1 - - [20/May/1999:19:20:29 +0000] "POST /admin/ HTTP/1.1" 401 0
    +127.0.0.1 - mike [20/May/1999:19:20:31 +0000] "POST /admin/ HTTP/1.1" 200 0
    +
+ +

The host field will normally only be an IP address unless you +have changed the HostnameLookups directive on in the +cupsd.conf file. + +

The group field always contains "-". + +

The user field is the authenticated username of the requesting user. +If no username and password is supplied for the request then this field +contains "-". + +

The date-time field is the date and time of the request in Greenwich +Mean Time (a.k.a. ZULU) and is in the format: + +

    +[DD/MON/YYYY:HH:MM:SS +0000]
    +
+ +

The method field is the HTTP method used ("GET", "PUT", "POST", etc.) + +

The resource field is the filename of the requested resource. + +

The version field is the HTTP specification version used by the +client. For CUPS clients this will always be "HTTP/1.1". + +

The status field contains the HTTP result status of the +request. Usually it is "200", but other HTTP status codes are possible. +For example, 401 is the "unauthorized access" status in the example +above. + +

The bytes field contains the number of bytes in the request. +For POST requests the bytes field contains the number of bytes +of non-IPP data that is received from the client. + +

The error_log File

+ +

The error_log file lists messages from the scheduler (errors, +warnings, etc.): + +

    +level date-time message
    +
    +I [20/May/1999:19:18:28 +0000] Job 1 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:21:02 +0000] Job 2 queued on 'DeskJet' by 'mike'.
    +I [20/May/1999:19:22:24 +0000] Job 2 was cancelled by 'mike'.
    +
+ +

The level field contains the type of message: + +

    + +
  • E - An error occurred. + +
  • W - The server was unable to perform some action. + +
  • I - Informational message. + +
  • D - Debugging message. + +
+ +

The date-time field contains the date and time of when the page +started printing. The format of this field is identical to the data-time +field in the access_log file. + +

The message fields contains a free-form textual message. + +

The page_log File

+ +

The page_log file lists each page that is sent to a printer. +Each line contains the following information: + +

    +printer user job-id date-time page-number num-copies
    +
    +DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 0
    +
+ +

The printer field contains the name of the printer that +printed the page. If you send a job to a printer class, this field will +contain the name of the printer that was assigned the job. + +

The user field contains the name of the user (the IPP +requesting-user-name attribute) that submitted this file for +printing. + +

The job-id field contains the job number of the page being printed. +Job numbers are reset to 1 whenever the CUPS server is started, so don't depend +on this number being unique! + +

The date-time field contains the date and time of when the page +started printing. The format of this field is identical to the data-time +field in the access_log file. + +

The page-number and num-pages fields contain the page number +and number of copies being printed of that page. For printer that can not +produce copies on their own, the num-pages field will always be 1. + + + diff --git a/doc/sdd.html b/doc/sdd.html new file mode 100644 index 0000000000..5c99b58e1a --- /dev/null +++ b/doc/sdd.html @@ -0,0 +1,473 @@ + + +DRAFT - CUPS Software Design Description + + + + + +


+

DRAFT - CUPS Software Design Description


+CUPS-SDD-1.0
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Design Overview + +4 Detailed Design +
+
A Glossary + +
+

1 Scope

+

1.1 Identification

+ This software design description document provides detailed +information on the architecture and coding of the Common UNIX Printing +System ("CUPS") Version 1.0. +

1.2 System Overview

+ The Common UNIX Printing System provides a portable printing layer for + UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

1.3 Document Overview

+ This software design description document is organized into the + following sections: +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Design Overview
  • +
  • 4 - Detailed Design
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+ The following CUPS documentation is referenced by this document: +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.0: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.0: CUPS Software Design Description
  • +
  • CUPS-SPM-1.0: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.0: CUPS Software Security Report
  • +
  • CUPS-STP-1.0: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.0.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+ The following non-CUPS documents are referenced by this document: +
    +
  • IEEE 1387.4, System Administration: Printing (draft)
  • +
  • IPP/1.0: Additional Optional Operations - Set 1
  • +
  • IPP/1.0: Encoding and Transport
  • +
  • IPP/1.0: Implementers Guide
  • +
  • IPP/1.0: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
+

3 Design Overview

+ CUPS is composed of 7 software sub-systems that operate together to + perform common printing tasks: +
    +
  • Backends
  • +
  • Berkeley Commands
  • +
  • CGI
  • +
  • CUPS Interface Library
  • +
  • Filters
  • +
  • Scheduler
  • +
  • System V Commands
  • +
+

3.1 Backends

+ The backends implement communications over a number of different +interfaces. All backends are called with a common set of arguments: +
    +
  • Device URI - the Uniform Resource Identifier for the output device + (e.g. parallel:/dev/plp, ipp://hostname/resource +).
  • +
  • Job Identifier - the job identifier for this job (integer).
  • +
  • User Name - the user associated with this job (name string).
  • +
  • Title - the title/job-name associated with this job (name string).
  • +
  • Copies - the number of copies required (integer).
  • +
  • Options - the options associated with this job (space separated + option strings).
  • +
  • Filename (optional) - the file to print; if this option is not + specified, the backend must read the print file from the standard + input.
  • +
+ Backends are named using the method of the URI, so a URI of +"ipp://hostname/resource" would be processed by the "ipp" backend. +

3.1.1 ipp

+ The ipp backend sends the specified job to a network printer or host +using the Internet Printing Protocol. The URI is as specified by the +printer-uri-supported attribute from the printer or host. +

3.1.2 lpd

+ The lpd backend sends the specified job to a network printer or host +using the Line Printer Daemon protocol. The URI is of the form: +
    +
    lpd://hostname/queue
    +
    +
+

3.1.3 parallel

+ The parallel backend sends the specified job to a local printer +connected via the specified parallel port device. The URI is of the +form: +
    +
    parallel:/dev/file
    +
    +
+

3.1.4 serial

+ The serial backend sends the specified job to a local printer +connected via the specified serial port device. The URI is of the +form: +
    +
    serial:/dev/file?option[+option+...]
    +
    +
+ The options can be any combination of the following: +
    +
  • baud=rate - Sets the baud rate for the device.
  • +
  • bits=7 or 8 - Sets the number of data bits.
  • +
  • parity=even - Sets even parity checking.
  • +
  • parity=odd - Sets odd parity checking.
  • +
  • parity=none - Turns parity checking off.
  • +
+

3.1.5 smb

+ The smb backend sends the specified job to a network host using the +Server Message Block protocol, which is used by most machines running +Microsoft® Windows®. The URI is of the form: +
    +
    smb://hostname/queue
    +
    +
+ Usernames and passwords required to access the printer are stored in +an external file. +

3.1.6 socket

+ The socket backend sends the specified job to a network host using the +AppSocket protocol commonly used by Hewlett-Packard and Tektronix +printers. The URI is of the form: +
    +
    socket://hostname[:port]
    +
    +
+ The default port number is 9100. +

3.2 Berkeley Commands

+ The Berkeley commands provide a simple command-line interface to CUPS +to submit and control print jobs. It is provided for compatibility with +existing software that is hard coded to use the Berkeley commands, +however since printer options cannot be specified using the Berkeley +commands their use it not encouraged. +

3.2.1 lpc

+ The lpc command allows users and administrators to check the status +and control print queues. The version provided with CUPS supports the +following commands: +
    +
  • abort - Stops a printer or all printers and any active print jobs.
  • +
  • disable - Prevents new jobs from being submitted to the specified + printer or all printers.
  • +
  • down - Stops a printer or all printers after completing the current + print jobs.
  • +
  • enable - Allows new jobs to be submitted.
  • +
  • start - Starts a printer or all printers.
  • +
  • status - Shows the status of printers and jobs in the queue.
  • +
  • up - Starts a printer or all printers.
  • +
+

3.2.2 lpr

+ The lpr command submits a job for printing. The CUPS version of lpr +silently ignores the "i", "p", "t", "m", "h", and "s" options. +

3.2.3 lprm

+ The lprm removes one or more print jobs. +

3.3 CGI

+ The Common Gateway Interface (CGI) programs provide a web-based status +interface to monitor the status of printers, classes, and jobs. +

3.3.1 classes

+ The classes CGI lists the available printer classes and any pending +jobs for the class. The user can click on individual classes to limit +the display and click on jobs to see the job status. +

3.3.2 jobs

+ The jobs CGI lists the queued print jobs in order of priority. The +list can be limited by printer or job. When the user displays the +status of an individual print job all job options are displayed. +

3.3.3 printers

+ The printers CGI lists the available printer queues and any pending +jobs for the printer. The user can click on individual printers to +limit the display and click on jobs to see the job status. +

3.4 CUPS Interface Library

+ The CUPS interface library provides common convenience, HTTP, IPP, +language, MIME, PPD, and raster functions used by the CUPS software. +

3.4.1 Convenience Functions

+ Convenience functions are provided to submit an IPP request, send a +print file, cancel a job, get a list of available printers, and get a +list of available classes. +

3.4.2 HTTP Functions

+ The HTTP functions provide functions to connect to HTTP servers, issue +requests, read data from a server, and write data to a server. +

3.4.3 IPP Functions

+ The IPP function provide functions to manage IPP request data and +attributes, read IPP responses from a server, and write IPP requests to +a server. +

3.4.4 Language Functions

+ The language functions provide a standard interface for retrieving +common textual messages for a particular locale and determining the +correct encoding (e.g. US ASCII, ISO-8859-1, etc.) +

3.4.5 MIME Functions

+ The Multimedia Internet Mail Exchange functions manage a MIME type and +conversion database that supports file typing by extension and content, +and least-cost file filtering from a source to a destination file type. +

3.4.6 PPD Functions

+ The PostScript Printer Description functions manage PPD files, select +options, check for option conflicts, and emit selected options in the +correct order. +

3.4.7 Raster Functions

+ The raster functions manage streams of CUPS raster data (described in +the Interface Design Document) used by non-PostScript printer drivers. +

3.5 Filters

+ The filters implement file conversion services for CUPS. All filters +are called with a common set of arguments: +
    +
  • Printer name - the name of the destination printer (name string).
  • +
  • Job Identifier - the job identifier for this job (integer).
  • +
  • User Name - the user associated with this job (name string).
  • +
  • Title - the title/job-name associated with this job (name string).
  • +
  • Copies - the number of copies required (integer).
  • +
  • Options - the options associated with this job (space separated + option strings).
  • +
  • Filename (optional) - the file to print; if this option is not + specified, the filter must read the input file from the standard + input.
  • +
+ Filters are added to the MIME conversion data file and implement all +necessary conversions from one file type to another. +

3.5.1 hpgltops

+ The hpgltops filter converts HP-GL/2 files into PostScript. +

3.5.2 imagetops

+ The imagetops filter converts image files into PostScript. +

3.5.3 pstops

+ The pstops filter inserts printer-specific commands from PPD files and +performs page filtering as requested by the user. +

3.5.4 texttops

+ The texttops filter converts text files into PostScript. +

3.6 Scheduler

+ The scheduler is a fully-functional HTTP/1.1 server that manages the +printers, classes, and jobs in the system. It also handles a simple +broadcast-based directory service so that remote print queues and +classes can be accessed transparently from the local system. +

3.6.1 Authorization

+ The authorization module is responsible for performing access control +and authentication for all HTTP and IPP requests entering the system. +

3.6.2 Classes

+ The classes module is responsible for managing printer classes in the +system. Each class is a collection of local and/or remote printers. + The classes module also reads and writes the classes configuration +file. +

3.6.3 Client

+ The client module is responsible for all HTTP client communications. + It handles listening on selected interfaces, accepting connections +from prospective clients, processing incoming HTTP requests, and +sending HTTP responses to those requests. The client module also is +responsible for executing the external CGI programs as needed to +support web-based printer, class, and job status monitoring. +

Once authorized, all IPP requests are sent to the IPP module.

+

3.6.4 Configuration

+ The configuration module is responsible for reading the CUPS +configuration file and initializing the appropriate data structures and +values. The configuration module also stops CUPS services before +reading the configuration file and restarts them after the +configuration file has been read. +

3.6.5 Directory Services

+ The directory services module sends and recieves printer state +information over a broadcast socket. Remote printers and classes are +automatically added to or removed from the local printer and class +lists as needed. +

The directory services module can only recieve printer state +information over a single UDP port, however it can broadcast to +multiple addresses and ports as needed.

+

3.6.6 IPP

+ The IPP module handles IPP requests and acts accordingly. URI +validation is also performed here, as a client can post IPP data to any +URI on the server (which might sidestep the access control or +authentication of the HTTP server.) +

3.6.7 Jobs

+ The jobs module manages print jobs, starts filter and backend +processes for jobs to be printed, and monitors status messages from +those filters and backends. +

3.6.8 Main

+ The main module is responsible for timing out and dispatching input +and output for client connections. It also watches for incoming +SIGHUP signals and reloads the server configuration files as +needed. +

3.6.9 Printers

+ The printers module is responsible for managing printers and PPD files +in the system. The printers module also reads and writes the printers +configuration file. +

3.7 System V Commands

+ The System V commands provide a robust command-line interface to CUPS +to submit and control print jobs. +

3.7.1 accept

+ The accept command tells the scheduler to accept new jobs for specific +printers. +

3.7.2 cancel

+ The cancel command tells the scheduler to cancel one or more jobs that +are queued for printing. +

3.7.3 disable

+ The disable command tells the scheduler to stop printing jobs on the +specified printers. +

3.7.4 enable

+ The enable command tells the scheduler to start printing jobs on the +specified printers. +

3.7.5 lp

+ The lp command submits submits files for printing. Unlike the +standard System V lp command, a single CUPS lp command will generate a +separate job ID for each file that is printed. Also, the Solaris "f", +"H", "P", "S", and "y" options are silently ignored. +

3.7.6 lpadmin

+ The lpadmin command manages printer queues and classes. The Solaris +"A", "F", "I", "M", "P", "Q", "S", "T", "U", "W", "f", "l", "m", "o", +"s", "t", and "u" options are not supported, and new options "P" (PPD +file) and "F" (filter) are provided to configure CUPS-specific features +such as PPD file and conversion filters. +

3.7.7 lpstat

+ The lpstat command lists printers, classes, and jobs as requested by +the user. +

3.7.8 reject

+ The reject command tells the scheduler not to accept new jobs for +specific printers. +

4 Detailed Design

+

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.
+
+

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 Printer 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
+
PCL
+
Page Control Language
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/sdd.pdf b/doc/sdd.pdf new file mode 100644 index 0000000000..d3f575b0c3 --- /dev/null +++ b/doc/sdd.pdf @@ -0,0 +1,989 @@ +%PDF-1.2 +%âãÏÓ +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +4 0 obj<>endobj +5 0 obj<>endobj +6 0 obj<>endobj +7 0 obj<>endobj +8 0 obj<>endobj +9 0 obj<>endobj +10 0 obj<>endobj +11 0 obj<>endobj +12 0 obj<>endobj +13 0 obj<>endobj +14 0 obj<>endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj<>endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj<>endobj +22 0 obj<>endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj<>endobj +26 0 obj<>endobj +27 0 obj<>endobj +28 0 obj<>endobj +29 0 obj<>endobj +30 0 obj<>endobj +31 0 obj<>endobj +32 0 obj<>endobj +33 0 obj<>endobj +34 0 obj<>endobj +35 0 obj<>endobj +36 0 obj<>endobj +37 0 obj<>endobj +38 0 obj<>endobj +39 0 obj<>endobj +40 0 obj<>endobj +41 0 obj<>endobj +42 0 obj<>endobj +43 0 obj<>endobj +44 0 obj<>endobj +45 0 obj<>endobj +46 0 obj<>endobj +47 0 obj<>endobj +48 0 obj<>endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj<>endobj +52 0 obj<>endobj +53 0 obj<>endobj +54 0 obj<>endobj +55 0 obj<>endobj +56 0 obj<>endobj +57 0 obj<>endobj +58 0 obj<>endobj +59 0 obj<>endobj +60 0 obj<>endobj +61 0 obj<>endobj +62 0 obj<>endobj +63 0 obj<>endobj +64 0 obj<>endobj +65 0 obj<>endobj +66 0 obj<>endobj +67 0 obj<>endobj +68 0 obj<>endobj +69 0 obj<>endobj +70 0 obj<>endobj +71 0 obj<>endobj +72 0 obj<>endobj +73 0 obj<>endobj +74 0 obj<>endobj +75 0 obj<>endobj +76 0 obj<>endobj +77 0 obj<>endobj +78 0 obj<>endobj +79 0 obj<>endobj +80 0 obj<>endobj +81 0 obj<>endobj +82 0 obj<>endobj +83 0 obj<>endobj +84 0 obj<>endobj +85 0 obj<>endobj +86 0 obj<>endobj +87 0 obj<>endobj +88 0 obj<>endobj +89 0 obj<>endobj +90 0 obj<>endobj +91 0 obj<>endobj +92 0 obj<>endobj +93 0 obj<>endobj +94 0 obj<>endobj +95 0 obj<>endobj +96 0 obj<>endobj +97 0 obj<>endobj +98 0 obj<>endobj +99 0 obj<>endobj +100 0 obj<>endobj +101 0 obj<>endobj +102 0 obj<>endobj +103 0 obj<>endobj +104 0 obj<>endobj +105 0 obj<>endobj +106 0 obj<>endobj +107 0 obj<>endobj +108 0 obj<>endobj +109 0 obj<>endobj +110 0 obj<>endobj +111 0 obj<>endobj +112 0 obj<>endobj +113 0 obj<>endobj +114 0 obj<>endobj +115 0 obj<>endobj +116 0 obj<>endobj +117 0 obj[11 0 R +12 0 R +13 0 R +14 0 R +15 0 R +16 0 R +17 0 R +18 0 R +19 0 R +20 0 R +21 0 R +22 0 R +23 0 R +24 0 R +25 0 R +26 0 R +27 0 R +28 0 R +29 0 R +30 0 R +31 0 R +32 0 R +33 0 R +34 0 R +35 0 R +36 0 R +37 0 R +38 0 R +39 0 R +40 0 R +41 0 R +42 0 R +43 0 R +44 0 R +45 0 R +46 0 R +47 0 R +48 0 R +49 0 R +50 0 R +51 0 R +52 0 R +53 0 R +54 0 R +55 0 R +56 0 R +57 0 R +58 0 R +59 0 R +60 0 R +61 0 R +62 0 R +63 0 R +64 0 R +65 0 R +66 0 R +67 0 R +68 0 R +69 0 R +70 0 R +71 0 R +72 0 R +73 0 R +74 0 R +75 0 R +76 0 R +77 0 R +78 0 R +79 0 R +80 0 R +81 0 R +82 0 R +83 0 R +84 0 R +85 0 R +86 0 R +87 0 R +88 0 R +89 0 R +90 0 R +91 0 R +92 0 R +93 0 R +94 0 R +95 0 R +96 0 R +97 0 R +98 0 R +99 0 R +100 0 R +101 0 R +102 0 R +103 0 R +104 0 R +105 0 R +106 0 R +107 0 R +108 0 R +109 0 R +110 0 R +111 0 R +112 0 R +113 0 R +114 0 R +115 0 R +116 0 R +]endobj +118 0 obj<>endobj +119 0 obj<>endobj +120 0 obj<>endobj +121 0 obj<>endobj +122 0 obj<>endobj +123 0 obj<>endobj +124 0 obj<>endobj +125 0 obj<>endobj +126 0 obj<>endobj +127 0 obj<>endobj +128 0 obj<>endobj +129 0 obj<>endobj +130 0 obj<>endobj +131 0 obj<>endobj +132 0 obj<>endobj +133 0 obj<>endobj +134 0 obj<>endobj +135 0 obj<>endobj +136 0 obj<>endobj +137 0 obj<>endobj +138 0 obj<>endobj +139 0 obj<>endobj +140 0 obj<>endobj +141 0 obj<>endobj +142 0 obj<>endobj +143 0 obj<>endobj +144 0 obj<>endobj +145 0 obj<>endobj +146 0 obj<>endobj +147 0 obj<>endobj +148 0 obj<>endobj +149 0 obj[118 0 R +119 0 R +120 0 R +121 0 R +122 0 R +123 0 R +124 0 R +125 0 R +126 0 R +127 0 R +128 0 R +129 0 R +130 0 R +131 0 R +132 0 R +133 0 R +134 0 R +135 0 R +136 0 R +137 0 R +138 0 R +139 0 R +140 0 R +141 0 R +142 0 R +143 0 R +144 0 R +145 0 R +146 0 R +147 0 R +148 0 R +]endobj +150 0 obj<>endobj +151 0 obj<>endobj +152 0 obj<>endobj +153 0 obj<>endobj +154 0 obj<>endobj +155 0 obj<>endobj +156 0 obj<>endobj +157 0 obj<>endobj +158 0 obj<>endobj +159 0 obj<>endobj +160 0 obj<>endobj +161 0 obj<>endobj +162 0 obj<>endobj +163 0 obj<>endobj +164 0 obj<>endobj +165 0 obj<>endobj +166 0 obj<>endobj +167 0 obj<>endobj +168 0 obj<>endobj +169 0 obj<>endobj +170 0 obj<>endobj +171 0 obj<>endobj +172 0 obj<>endobj +173 0 obj<>endobj +174 0 obj<>endobj +175 0 obj<>endobj +176 0 obj<>endobj +177 0 obj<>endobj +178 0 obj<>endobj +179 0 obj<>endobj +180 0 obj<>endobj +181 0 obj<>endobj +182 0 obj<>endobj +183 0 obj<>endobj +184 0 obj<>endobj +185 0 obj<>endobj +186 0 obj<>endobj +187 0 obj<>endobj +188 0 obj<>endobj +189 0 obj<>endobj +190 0 obj<>endobj +191 0 obj<>endobj +192 0 obj<>endobj +193 0 obj<>endobj +194 0 obj<>endobj +195 0 obj<>endobj +196 0 obj<>endobj +197 0 obj<>endobj +198 0 obj<>endobj +199 0 obj<>endobj +200 0 obj<>endobj +201 0 obj<>endobj +202 0 obj<>endobj +203 0 obj<>endobj +204 0 obj<>endobj +205 0 obj<>endobj +206 0 obj<>endobj +207 0 obj<>endobj +208 0 obj<>endobj +209 0 obj<>endobj +210 0 obj<>endobj +211 0 obj<>endobj +212 0 obj<>endobj +213 0 obj<>>>>>endobj +214 0 obj<>stream +xÚíßoä8rÇ%µúeždïö;ݞ 3Óö¸go€ h“y+Iòäá°;wÙàr{73w‡ûïãþáný ¥ª"%Q>sÝµMµø‹ß*’EõŸ_]‰õã?Wâ‡kñþƒøéÿ^ÝÉW‰|õgñ~ý›·?ìþøþÇ·kñ›o¯ÅõõÕۛ]­Oïîóÿz÷é]öïwbó¯ë]y¿+våã®Üïʏ»òoÿýî“øöå/Ÿßý§¸yõî?ÄæêêÝ܋ñéáUñ< ¼p™ùp½\./ζåñ–7Sç’÷˳ÈS•³óˇirÉë 5R ny31.yÝÅôTÎ/“©pá¡h7S຿ðÈÅ_&ŽsÝE¯œoæºæRÙ4Gp¦¯ìö™e®{ᙗïǸò ÏJñ/âºö¬•`㠗žÍré—±^Øí2K\ò³^ü×£så‘×Gùnd®;¯§$cr]y½3—e´nc=–×£pÉÈó\'…°Z¾œk,L‹SÀb€Ó’Á˜–ç­âêÝo™9h6×ÀX`É\koð ÀuëPf½seÞ(åûž¹òh.‚(‚û +ÏÒ˜‚2´&¢Ô!FçʽQ˦/®h\.äƒ 8dŽƒix.²Ø¹äøXžß—p€Ë ­sežec™KFnp–¹Öž#ea•+óœ)‰E.W¬åÄ\±çPÙXãÊ]Âꔘžh ¢˜ h`¢˜T¤×z,WêVG‡Áô4Õa0AÇ8g—t«5®‡)jt Ï½B<×LÏ?=¢ˆ2ùα‚ä¹v%”ïàòô\Ùá³rŠ"J¨âŠˆfØÉµÒríï5ßÿ +¿d×)l3—¤ša'W¨çZïDsÕh¹ÍWpeT3ìäòõ\û›=§Rì•,×ìX[ɵ7Ž3êÊ12BªW +,×0§÷óâ2W5#jÝCF#ÐSÅjåVåáëe®¸bØi©€–Cíäïô^“×…’K6¸¢Šåå=¤j:êÕÛI¾{ñ©>ÀR*Wʔ粬îquGó~1©X™&É%xQ”ó\/ŠrKšÈ¡Ã\¹¡ºÊ•q£CǹÒç&‡®˜ºÍµæG‡Ns‰ç&ó®è¹É။³4?.ùìd~ϕ=;™ÇrMBæË“@À¹e÷£y¹ÿ¶’óM‰+fË|¹ÎùFõ[ïì²²ìwZímçSFÛ]iYç–W®ÓºM}p&J®‡k¡æ*¤ï\‚í¾ÔøÕ©5qÆáš)¹rõþrÄv_jךèq¸<%—Pï;ðmÔöªËM­5qÅáZ)¸Ò¦ÊÊ-X®™&|Y©¸BW¨àŠšÑ2×Þ`u¹sµ&® Éõ$þYt´{@¹å͵Rsù*®úq>Wã àQηþä>:˜ ŽkÞʵû¿{áUZ0¯:–DŵPº¢j<Џ¨ìdž6Ûn,º¹/Ÿ5vn½Êñ€rg®ÆEYÅn¨Eì‚«”–RíâSnO½‰‡«qQuÓéÇ¨0jƒá:¥)²äçÊ&®8\õ‹D50ßфP϶sI W¬ç +9\õ‹j#eg– Â¨ÃuúA‘ý¯æò9\µ‹êO%žËïƒKqœ¯›KqQVw°ËÇr ˜ð00çjê†â8_7—î `¨š/{v¸¤†k­ÖyÅq>Wó¢Xé`F……‰FǜÛj›Çù\͋„Ò¡¸æ(®Lí¿2M¥8·àj^¤åÊ,qÅÊxãþ†ÔšØ<·àj^)Šká’^C‘[ç)Šã|®ÆEZ®”F•ÚpøŠÆz^©8·áj\T®~º#ŠkSοÊ&6Žóa¸i¹€FêŽÑ¬ª6šxmWý"®Íª~ë'š&֏ó¡¸êi¹b‹\u/&ê&֏ó¡¸êi¹Öüð°Pœfy¿ÑÄúq>Wý¢¨–¦zäÖ¸üDÃU +U+M¬çÃqÕ.âsH.UúíÁ/–=ê&֎óá¸j‰’bW¸";\¥üÃr¼±_öÕM¬çÃqÕ.jÄQ)–+,pó”BÅUz?”¢‰;ѦrU/Z×#¢øÀåõ˕µqUó!¹gËM\c¹æF\¹.ž?•‚ÈU½(­•hÏ%{撚SŠã|H®êEYM²¥‡åZq­\Àáª\$k¡yêWÎáª^U˜8puç®zäªçÃrU/ŠÉø\Ù¸\1‡«rQzÚU>-òŽÎ•q¸*Ér+³c¼a2­´À%9\ՋÄiÿëÎ#p%}r•ó¡¹ª¥ýJ¸RWõ¢Z$(v\&ÓeWÔΕs¸ªUgÆáÚ ®Òq>WJ©;.×Ýîfþ%¦¹”º#s]ԏ¯U_6TzÜ¢®z7@½Så)Ji[gÌ%éÕ<ýòöT³.ƒkS] í‰ë¶9£©¾Ì+?mvÜbNTur­ª´.©ØQª¾Ð0=.ñKÔÉ£N®Å\ šZ‹ò«¥oÔê2¸æEehöé¶Ê <¢JšL½.ƒ+¬ZJ/\ùÓÆÓY¹nùÕµ§Ýze]WP¹u?\éq£P^•nZ’ÀSv…².Ÿ+ë“+.íX¯OÞ¥ä²NÉ皺ªe~õ]«Û;iŸ\¢$ò4ªNXz!³¦.Ë?nŸ>â 7®¨¼ 'jJ2ž¤¥.+8>ޏ‹Ë$ž¯üNjq`Y5I[U—Ä5;>ŽÇ'՞~:¦À@5I[U—Ä–Ý܌«#ýðøçüì±,Jb•”ÎHé뒸¶ç¿ŽiÑ+W ûÖ§”Tܶԏç‡Aº«޸"]:ÎaO9/ÁD-©;x®õá󶟼ék n4qcPFÚº$®ø C[KOzã:ìužoÔÖ.“âIεuI\pÊ~õ‹Þ¸Ž!z£µû/~ˆJ¾X_WÉÕLìÜQ¤‡ñºu_ýq•òAj­Ÿ¼ÍÑëëR¸²ƒ¬·lÆÕ¶¯W®Wy/qÚÌ¢ÕÖ¥p凷nِ«m6Vžã¨LŽ“Îº.é_ˆ>oç2Ú_–ÚÌRÑÈjÑ×%pǼûm\µ,Z?iôdˆ¨KáÚ;æ[ô¢­*…êKætu)\{ǜí||Ÿ\Oa¹TªdÓÖº8®½cÎvõ͸:ó¾î"Õ¨ʇ¢®‹÷Ë;7˜lÿíwpÙÈg»¿hNjRÍ$GU—À•î,pç–ûç:µvV ¥6¨º®½cÞ¹å!¸žD!К¶º®½cÞ¹eC.ì»E³v1h«Kà’O^l>×)ñº›«V—ÀµwÌ{‘lå2ÉÇÞ¾JfUuÅZ®¶º®G òÓúi/\U÷ +‹ºº®GÉð³½c4äJpë‡\mu)\۞N½ã‹êzã +*¶å·réêR¸`Öïâ29w#*­:ßV—•îOÖæ\«öé×¢<™i¹ÚêR¸²“Sï+-÷çºv›ZcÛêR¸òÓl •ËäâþZÿæ´©µÒrµÕíˆç+oےÕ]A®Eç>ìiR?Yl«Ká*½¶?®¸e®Vçj©Kâ8.£sÙyKÕ:WK]WbÎ5Ç¥ÛÔCÿF¬¢¯K⊿é+×+Lƒ+ç®GU)àøTZ¹ŒÞ¿Q]‹ù¾håÒ×%qéÞÏj—«ÔØË¢ƒK[—Ä•}z;—ÑBöÖ]Dڍ“ºFÅð½=‡Bùz½a¾ŠÏð=KÎÃ÷b½p ÏÕýºåirÅÿ°\É$¹º86“ä2™0¿p Ïe4±œ4×|’\ò–+œ$W÷löL¹‚irEÏ0ð5ü>Ž®¸ÖÏ0ðÅ}Ïj’\ðL¹Òg ~¯ÙX¥ëe¯ Ãï¡«t5y…ûÞ@ç©Ô—sT—Ô%†ßË9V‰Q\Ñ䎮Pû½·®¢Ë¾ßSìÚJ[Ô¥Èï•v-àðP\0µ€Cvú[ä÷›;pd8®É}}ÚÙ €‰¶œsÌÐ9lc®Î9æu§ÌF^œs`¢Ó-Æ8çÀ¢Î^¿k¬;씽:æÀòn5”¾86³ÌºÕPþÀ1–v7PÀ1w  Ö±غ;êTé˜Ý"8átKèmœ£sJès„m®gú ¡€S§„A:àª:%ô1¢©€ìZ—„^ L CÑ¥ˆ>êv_O\rBB/1Ò Vè瓑ÃU‰KLGS̈dÈå Æ…ƒ+ôÞTäÐ/seÓD”aAzG"ÄñAúp"r8/s!„Þá”]AzG„cÒ@«§+Â!f_%®t"‘T§ì· À }8 Ùª\¡&!a• ±tãOB6æ5.1 áˆp*øáDÄ!‘ð†ë„pdH/ „+\ŽÙF(‚èÀbv§ +Ìê\AtÀ3c—+  âÜýáµjpÅ`è³ @Xq ¤GŸµ†‚$c0ô;  ÇȬûÑÏ\Âù†O¼’ñŽ=ÀÖèM8Æ`øÈHÎaä–á§R@Š•G`„ÝG ©èÈ!"a +¢pŒ8À(›t@ëçQç`”= ^8æ"GLhutÌEÊR;æˆJŸS {zD¥'­HõÒñ”^PšT%mµM’4 ¨Cs4CDØÒL˵v×iË/PÐØÂQ3,ÇB@vé#bJ3$ ÏpF2Ä5íy݊G1DI ]<ÅÇSâㆂ1ÀFˆqx@Á`¡‹fX™içÁ ?YI© +Î|Ö,¨jk€ œd™‘½¬6° ‹ÉcX]>°rHz‹€5DVFÔ +œéöÐ1‡  à, sd Þ Tê׌ÌÇ3 ÔKÎcîç $ÆÇÜa:\‡±†;peu°õfŽàB*ý@±ž1ð?j˜c† À©ÃtXÄ ë€í‡é°”éL/AƒÈ!Qà¸ÖX°•Ý5CreŽt˜Œ¸A8F†Xûª¥qB Õ, +3Cìuâ,ùV…™!öªõا»@sá ±GéÈ l +SCô“‘5^)^`&°}Zâ­Ç7C-—ôƶÄÜHº 06Ğ4QùP0´=yg´ªWÆÀxÔöãsCkc_ßË“‘¡l'fƲ6}¤`aàÚ÷bw„T®”Ôa6µƒ¢Y!™Kz#ÉÈ|€#· &……›‚%s°P‘Æõ‚ÁE»Ãcùn`)l uÀÂêBÉ*ÌUñʎ‰€ùªE0–>+ë %w²K/U`+J;‚½H Û7ƒÁ¢6™ª«å4Øóü'ëàÙbQo²¹ŠˆVÿ¦sT¹¦ßfÃçJY\žCí,†Å·Å]\Ìó¼ó¤çÎjŸurÅ·à¿tþ^°†qaÂ%=~9GYc~Áûô•—A‡mÇÙe—9Þ3©:¦Ý\&¶G{ÐöuÄþ܅!u¦4ÈˇF¿Éûedò¸ +S®Ü³SÎΗËåë‡Çr¿\^D†Ÿ¶0æ²ÑaÖKWþ#†K:ȵ°Àe&‰£tŽË½[Yár®Ãº—¾p\rj݅ä"ìÚ Q zH®"r‰kc+›Vw¡¹X+=i|b“+w†kQØärFëqÛx.MEãi\Ü%œDƒÆå„t`÷{)\r2VHãrÀÑ[‡$®Ñ-Ÿu@ãÊ'b…T®‘ã_Â6‘kTK¤ä¾P¹ÆôΔí'*׈=)iŽÌ5Ú£¥½Ð¹FbÄÄ2×8CŒ¸·ËàeˆQ³ 8\”ôÀ14ƒÍ5¸vÐSåx\k#É%…»RhÂ5¤(²R‡¹\Áñ2ÉØ\Œ´ŸA—1×@“1扮!ü³Ï=HaÂÕ¿)ò³4¸ú3H>5ãêWM’… ¹útÐF9Ц\ý™%ãs‘s¨{š˜ØçêcÚb˜®n‡Ë¾,šŸ›°ÂUH»¶xiÞ";\¶h¯Ë‚MáW!/Üé,›\–ºì|S¸ÆUÈkc|m«-6¹ø©ÕªK{-±Ëe^HÝ“‹Kf—ª.ÙùkÛm胋˜ï/{xÏE?\å—ïŸßôrûÞ¸v½Öagˇ¾îÝ'×®Û®—gê~º|èó¾}sí;n{Âayq¶-çËååÃCï·„k„ɧWé«;ùêݏÅÕG!'n®ÅÍú퍐?ÿÓCvû£oÄ}¹ÈýÝ·¿ýöËgñðùë/¿ÿãö??}ùåOß~ùõÿ,ÿ÷ñnÄÕÕö®>¼ûA¼¹zÿözû!ۋßäo®Þ®·ß\ݼýA¼¹þ°¿GòÛ¯?}6|ùõç¿üôíë®âMõs~ýÓß¿üòûÿùöØÎ?¼yü×Ç·øƒÈ¶¿ü*²Ï_?ùë矷—&ò‘êÿTMòšendstream +endobj +215 0 obj +6311 +endobj +216 0 obj<>>>>>endobj +217 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +218 0 obj +31 +endobj +219 0 obj<>>>>>endobj +220 0 obj<>stream +xڕU]OA}çWÜø¤IÙ²€}«¢†DíV°é/Ãì]˜:»w;3 ¡¿¾wfQJŒ$†¹_çœûÁïV þ‹á¢ ½ȼu9k}¾A<‚YƖÁEféi SI%žÍ~ÕÖóhXÛÛçèöˆb˜¤X8•))œ¢¢vîC7®ÝAí:[) –2·!E«–…ÿ'*} ¤$«œSAih­ØÂV'”ÆT‘‘ÉC~à[!#WÊ¡tgE +’RU,2€ëƽ¨ëëzç+ÊsŽ{z˜ü„Ä(†ËžÓ­u˜Ãüôäê)™žÌÏàëKÄQ':Bº7ڑî­Ñ¬nÞaý~õ®J2N,4ò[ã£Å 0õ;ÛaD0ڐÀF0q°ö€õÑ«»FÍ),¶p-ì¦;ýCi%GCNŽUëXIaÒ=Kº +²{BëšÅ‹”ŒõºÔ­,kWtÏÍ· áû#ôêÍ3jÜrÓòœÚZÈ]vh2!ÑFM֝Š!§®SM¼_n/&³q$Is3'׳›ö$I¸¢v_˓çñs)±ôþü¢E ¿+¬¸(p³èÜy\¡ 7b,Ð÷q~z—Œ?ÁãÍU_ŒægŸ`ÊCÀö{´V,.5Égv›Þ_z«¯ðµ,§üˆa¸T®ìW[:(i«ÒO7m£Ü + rŸøKVÒ7Bhå¶Gõijeِy®2¦…¡õ”=Š„¬›†}Ûszµ€¼ I2æEh³døj(Øý¬ÇÊ …®«Se©›S`¡*R¬‡÷8bfÏ]—ºª7@VÖQ®þpíu³Š”ÁíÃÜ®öÐç§²2†…ÞB ”²½úQ§7?;ÀëE¨Ü·)ãӏ“„‡D8ü¾@?d©ß‰³‚Šö+ÙYíûç¡ãÝ-ûÀøèYd?2KQ}…éÎHkڄUÅ0 öK]K6µºCæþRnÞ\À[0|æÛ¯½ÜƒÜév,Š“Â#fȝàý¯Ð‡Žk¦oõù`|?Ä7¿ u¢ÿŠÿÊñ·šx[Ͷ6 S»Q«3ðm}ó Øv¢gö¯þûõ¬õ½õ'(B‘endstream +endobj +221 0 obj +825 +endobj +222 0 obj<>>>>>endobj +223 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS046Ò3W072PIÑp rt QÐUp VÎO+)O,JUpI-ÎLÏQÉE™%™ùyš!Y\ººP­F 13=30ßP!89¿ $êÂÈäÀ"wendstream +endobj +224 0 obj +121 +endobj +225 0 obj<>>>>>endobj +226 0 obj<>stream +xÚ­•OÚ0Åï|Š9²Ò&K 7 +l…T´) {ââÆp•ØÔ6Úòíkc•V%]å@Æ¿7ö¼?ZtÌÀ „nòªõ)k=½ÄĐæMЃŒ¶CX`yŽê!ûîJžýÈyϑïÊüÆË$…‰ÈwrM4Ü-èAËþ+Ï6…(KñÎøÚ-¤— )µ.…o{ÐóU]3tàü#?<³Wa×Êm«àç‰ø¡Ó ^°õN:½9ád– IIø5ß4tÄßà³Éäžî•Æ +f\£,HŽ0AÅÖÜÞrɶ糹G"Í­„ÿ³…~'aD+ƙÒf/B*»—)ð¯·PÓ?¤õd~ H±–¤ª¬ w.n¡SÌw’é½±ïVH݀›%·¸ª¦I—˜ßRáÿŒímrûf¨ÖÛ¿Mîœ`ÏE§×)áUoPžb¬þ1Â\pï*Æ +l ™áÙt:…  üÞc° ç›Ý ¡×¶ŸU›JRèÕÃ]ç9K’§ÃÌG”2K$%¼nOèdxÆ^‚fì)ϵ=N!“„«» zbͪmyøÕ²ú¼c›qæ‚byh(Ŋ˜#ÌÕ] ÅËØ<âGøÂ8º1X¬ŒM̵ÈÅÑÛÑqÑÑ{aßúŸéE?6²æU×~žf­¯­_Ð&Ùûendstream +endobj +227 0 obj +522 +endobj +228 0 obj<>>>>>endobj +229 0 obj<>stream +xÚ-‹Á‚0DïûsÔÈ^U䬰~€©[S‹_«f&™ÌLޓÅGŒ²N¶wÚ +­º5˜!\š¼Ac +ÈeÑö›Naw: F7¿ÎQÑêä¯!…þ1û1,åFُÌþh•¶Êp^ãÛ zu5XÒµ:ÒŸ"${endstream +endobj +230 0 obj +125 +endobj +231 0 obj<>>>>>endobj +232 0 obj<>stream +xÚµVMsÛ6½ëWìø$Ϙ”%9úpNµÝtÔÉ$®#÷¤ D.%Ä$ 5þ÷ÝH™bc§j’Ñöë=<ìê±7„sú a:‚ñ’¢wµì >Ìa8‡eF'“é,ÓþnÐÊM ŸŸÐ[‡…·”F#‚St[4´Úʔ)8F¡JÐF–N–pÂ>ØË:©Sfñè%ûj4™Âamý+‘<`™ÚC?*y8&×לÐ<`ŽÏpM5ˆc½¯ÿXgϤ-JG¸E‚ðQ®0ÏG…ø sr?®Ì/ÉÓ*Gsœ—¿>ø»C iæ];´ŸÒ%ìáI­/ƒ­²®L]J'Âê4>DùÚ?Õº' þJ›² ’zï¯ú|C4ÿJö¹Ý[ +õ‰ª¯“Tü-¬U‰¤¾.µ†‚uÔ36ǦZJ—7i¯2òMÂk¥%Ú:㋪“°m𱒆2þoî>ëðnBU½Åjî?Ys|\jtöØôԓг³ê‡@"_ÖÅdtæ{=7÷÷ ³PFV¥r`5&¬¥ôÌûÔoŠÊ:bG¤~×GàÌ¢õñ3£ +oc5*aRjôÞ<ŠˆæÝþA_µ»—œ’ÎüÈ!ç‚“òƒÌ?ë»ÅÍ3jCüÔióä•Gv;Uå)¬¹DE‰¦a§û¬Ÿ}HŽpÒ ‹÷íÔy’Ç£xR·Rj¦dýf¥ó=UÖ£ò4\ú«v  D·Sæ!0ÈÒ3À(ZÐýL"3¸mfð­QN%*Ruà0!’õÕJVCìö´1ªŒŒl¥µ2.ÓRG²[W®uJ¿ÇÕr¾Éÿ,®>ÊOt|#0üu©Ùê0µ Bb¶jYñ¨¸lXš4¬Ðƃ +m‹ì±Â +»è½¤ÛøÇÐ 7IhŒþ¹¢qºç!Qe‰ ÷Š'):.û¸|¿õûq&ç!¿ó`>>>>>endobj +235 0 obj<>stream +xÚµWÛnÛ8}÷WÌcŠÖò-qâ‹EÒn±}(mìCÛŠE¬%R!)»ùûΐ’oIܤÛEØ¡†s9ç̌r×Á~F0™ò¯¬z—óÞàý F“d óœžMÏFü5;š$£äZ%ÊWóodv £Q4ꏧôŒŒæ¶& +¹@ÑŸ:sàùARå +3øfRð”F’im•öhA­Qz2X*±w¥õZë!Ã¥’˜EãL(~Ì7;ºùô”“‡Û¹±ÕyÌu³X•¹¶Ž>Ïäo«ÿ4µWF~?_'Iòu·Ô>_ß.6Z:BCŠ ô=UQ¥J >ß$R–f¥ôm›lݍÏ(‘µ¿/ãé)téFƒ£T4ÙñlܝYáq7­#èÃ5ú3_¶áúÃI‹×nì-Ô ¬¼Û| +äðì@hÝT)ñHUg `/‹Z «üý~\\¢~"*?‚x drA ÿސ&˞ˆHOþ€ÚèGH7–ĵŽðÍې›NíG-MÆÉ´ëÖpUz¸U«ôy}ªÑ¯Œ]@aœ‡ÆqlyvI|DçÄ-Â%µó‚ºÙx#MùV…’Å^‡Rw6Ž\§÷P±³JÈBit`­ÙïG%­q&÷_Æ'SøWé̬ý/ìð*= 8k-*Ü5ØàŽ¾¡‰À†Ž™YvŽª&T,Þ5ÊRÖ †”TnˆÞÍ-a 4oØ@iº +øÝ³£xª< j¸KÓÁ†þ0SÁä?‘uQ××ÑKǏªÊèò>P²Gô7®Jô¾EQ…Í(s\xk´úÞUï~‰—È5ŸÏy²ÿlÚf˜‹¦ôq ´Ã†‚ÎFÃáå“ä¬Cy¯rÐK´ ,ñÞRÍTˆ;÷ÚZ¶ÖŒÙRe4áÁ©ª.±{Ò/I½È…DfàíÍÕ5º&­”¨Ñf#ÔÚMÇLʏ÷ϕ´Q²0º)BMk$U%wÿJù‚„¥œgB¹AV¬;_ˆp³`‚¤É¢H‰ÏÀÃ:Þì…-Ì +¹…I%r#è­­¦çŶ‘ÙFPA¢SeCpª›o¢–¦±4²Ã]0NFPÖò 'ô¼‹‚÷i˜$6öªÈ*¥ Ú{†Ž‚0-c‹xá÷a´ú%Õ¼Ϛ€~ Ö55ËÏí.ö5ÏÝðë)/R3-ojJrÁå*×]«¤× !½Z⾒~¶}Öá2åDJòíÕååI…h\G[SÙA_A»>ªiwÎ<‘à Ó0+ýœ¢óø^Èç;ÝÉÆZJü—!@Ý"pU´®ŸJe©w¥¿Ì+©¬åQ°:ÄïÁ©Õ.¹-8Õ-9Ó¤ÝÑF¨€Ö›a¿,PS??÷³öÒhxL/ÓÙ0™±ÛwŸ.ÞÏÉKh“ën@½C§n5H«Â\a'”Ë89…þéxÈW§|v<áü†ý³ñ×¼÷Oï)~×Çendstream +endobj +236 0 obj +1084 +endobj +237 0 obj<>>>>>endobj +238 0 obj<>stream +xÚ­V]oÚ0}çW\ñÔJ!k€}ÜèǐV‰­™öÒ'q¨»Ä¡¶Cſ߱J;ؤ )Îý:ç_ó܋迈¦CM(-{Ÿãއ›KŠFáâß&³È>fgXÁC±VçñlÆEÞb0œ„ck?rûÒª,™ÌH×I)Œ&FOUBy¥h­„4B®B²¶óË{Úp¥E%©Ê¯—¦Ø’XÉJqM†}Ѩ¿¶c/e?°E µ¯3;ë?bÝæìë>Ukƒˆ:ô…†á¤3² ËShJR¼¬6¨¤’œ€¡DYˆ…µ—åc8k³\ú#ä˜ß.ަ˜ƒ,À¿e†¿°--¤á*g)§‡3¸>œ#UµR¬Ôöa#2:_x2H˜æ Ø0Sk—©P …Zæü÷²@µ«Ì”Lk®={¯½GÛ(ŒZ—£° Ÿ +¡o$Û0Q°¤àmÍÎä–Ö\fˆ«ÄIÆ´Á¼fjm˜ÄšH¡'ØÜÁR͊.4()„èBeB¯ ðlóµ!|2˜iΝ‘•«gîCç{” ü5 Ï5¯Ñ¼ˆÐ@H+4ߛJ ³õ€­—œpŽÉ¶ã !@H?ù!¦¥«Á¬÷aó æ[]1ĊÂݛmDLu´ñì!£NZGIiNêÃQuBí? ¤+âÿ(ä½ý?öCn·«¿ŠD1µ=>¬ËnKÞ¥ÝÿÚÍWԔVrÃ¥à2å}‰ãe@‹%.“«š­°x·¸»h¹¼ò»[1˜|äµL}Ÿkí¥eÚt•›tÿxÏǘó])tÓü#Æ}ë]zæÆªƒ˜9ªÝéaU +TÂP‚6:`¥ÐÈ5ÇiØn§¼ðÇL@+'¿mªüì}5sï•Ïž +›rŠ€¡£ÿ/Ûî:ÓìvªïV€­•<5öљCÓW¬Ðºæ-xWœe”1Ã(WU Þòðx´_0S¸·EØÖ²6kjkJ“\áwõýÓML/‡ûFtÅ5Ng{K•pCÂxßÁtxñæïÂxv^’[ŸÚ÷ë¸÷­÷{–žÊendstream +endobj +239 0 obj +808 +endobj +240 0 obj<>>>>>endobj +241 0 obj<>stream +xÚµVßsÚ8~ç¯ØG2ƒ ÞS. =nš+Wț_„$ƒZ[r%9iþûîJ68ôš¤í܄ɨòj÷û>í}é á þ a<¡/{®{§ó ŽÓ¬sü6™ éQôÇéY:†År óZs¯Œv'ëOh}Ãa´MF“ôŒl×;,óÆ*kûÞ@É4ÛFC+¿ÔÒyÌ3`ZóÞªMí¥àG&+Wá^é ·¦Fñ1j+úNÚ{iaÿƒUþ‰ë‘A´I#ò.Ïd>>>>>endobj +244 0 obj<>stream +xڍVËvÚ0Ýó³lÏ)N ”$Ë6é#«Ò†~€Ç [r¥qRúõ‘dB)käû˜«1?G%\ò§„« Lç ÛÑûåèâ㠔ÓbËš×æ×¥\V¯¦Å[¾0­Z#¹.¼^þàÊ”eªOæÅLê–|®‚Ú4„´³è)¤¹‹|mÉÁÂzÐÞtT¤G§“b>€O¡ g‘SÉklˆ¨g,ôãС6µŅ̃m•­¸Ð»‹»L‰ïA‡¾v¾å]™*ï4v *€ÇŸ=ÂJ80rbZ½Zm¼g´s*f@ø‹ÎêŠþ1PÎù÷¶¸oÒ#§LàAo°êô'ÃP†í€ºoší¸î­&ã¬jàór¹¸(‹X+3b݊€½d¯B4!{ހnTÈâê·ÆRr`^ز£m÷ª 6\{Á´]ƒ°òNUZ¯TÀ +*ãQ“óÛÈÁh&폭£L¸U}nifZÙÃÎ!(­1ÈsÉ+:åÑR³MÉAÓ¬;³<ÙÝ9Ûò®§óæ·¿N:­ö+¡u⺘î1tγâŸÄ!1‚‘ª„¼k¢4y +6:=F6¨&µIÖäÞ/Cˆ ÍÉ•ÿ§o·ÉʓÊ»_Ö#Ð9-»-)!ø ô&­¥8j×4£®>ЖúĚ/`? ÆŽðŠi󨪒'o(gx—gk³î}ö–OÝ9ƒ¦lacÏø#%'ìÙu0WʸêmîqˆGe8%a§¬XÉ Š;ÿŒ§èA­t<‹¡Ž¤žÅÙäeƒw2 É<¹žoJædƒ±ÌC."µ!Féx´/çÂ(N¬•cêîömÙ·#våˆ'ø uOC\y +¢—ytûéþ”¯½âùÍÛ"Vr²„¾ëœ'xÂU#9yNí¦RÔKH¬á!ÀEZøÅêçӋ՛خ¿NÏq„’bŒ‹IÞ¹üÌàv?s§côW:_N“D|ðíöûâáH¬£xjÌï\|à«êØY6Mñ¹ªñx&ßkê}²ªaõ¹¥Ç¨ÅΦ÷s¤‘§w€2MÜçyýaF&_ŠlAÕßGxLßF Ú’›pm-¹W0ŸMSî¾½û¸„qâøàjz’vÞa0k+_ñe›{3N{ÇW“Ëþ#Í®/‹ˆ«7òûÃrôuôHÆendstream +endobj +245 0 obj +911 +endobj +246 0 obj<>>>>>endobj +247 0 obj<>stream +xڕVÁ’Ú8½ó}$Uƒƒ!™c6l6³U[Å̞r²Œ•µ%G’¡øû}mÉLÂ&ÔLFju¿÷úµÌ—QNSüå4_ð¿lF¿mG¯?

Ïf´-±·¸Ïù±ϳEö–VÚ)¬;ÑF¹ƒ–Ê¿Ú~Ƒ7”çñÀd¶ÈÞðm¥¨8‡ûN-ºZá»)< S"´:`§uÚåÈiSZ׈ ­!{À² ³¢ÂòVþ«BFOª±A1Ž ‹qʳËZxäÂ)]°œQŠº>‘( +UP°d04¨QPélCÀk‹ 3¢s"ªµHæÉ(…ãY*ýsœ¥ƒÒ‰òmÆ^›=>¯ÖÔZGÅ[:\æÜ/ú€UÓÕA·8 žNE @ƒÓ\ø¶ã“ù,[ _Ðãz}µÅØøU(P£/9õ¥S½V(*$?Hi]Á„N=?=ÒAÔºˆt5¶ko©UŽ5@'*åÔãP^+ó=¾­U.†,‚9 sê3##7‘õ‡VŸÆÇJˊ½¯`]—jû`‚4$­ ÎÖìx¤B5x$ö¡ä¸‹Ú·ÛuJž}zuCÁ%ýiw×§ä3 aÄ~†~çŽíÁM+u=˜q'à2ö²Å<a78«¸ë£k4 é/h°ë:F‚¾d2¿õ*•ò_×ò·¬rO m®m0EËaËÖ¯wøÊøƒn`²]è Ú·"Ȋ״iÓ*vù‘ã£1¸{‡vùŒCï¤ ªGΓTÒFÚ¾N„:MPǛÇ?>>_x} »ì ¦›ªÆ€ù¯½…Ú¥Þw.º²©_®Z§«êªjçûìÇÊõ®aNßÜ}ëõ*AÒi Np~“Ñw²^ÖO£S"ÝÑG§ƒŠÄÏçþOý…ï[¸!ñ}ˆDæ„M_žþ¡÷¶ââ:ís´LÑìö¦W‚³»Î‡agRkÃ×'`•B*÷Ïë ún×èhœaÈ_&ëz–YÞßm¸ +3† P(¨ºNãXY×ßL1ʨcœRnšoñ(µæ@l{®± ·z”M—ºÝ§‚9@-i±˜£(ºzz÷aK“h‰-Ñù­O6H§[¶0'™Ä³“ålÊGó)/ΗSðÞúôûvô÷è?¢÷†endstream +endobj +248 0 obj +920 +endobj +249 0 obj<>>>>>endobj +250 0 obj<>stream +xڅTQoÚ0~çWœòT$È À»1´>L¢#l/}1ɅºsìÔvZñïwgCDÙŠtI|ç»ï¾ïì×^·ôd0Áx +EÝû’÷>-?C6NGWä›Î3þ,oÆé,j±UØÏ_(lYƒ†£)ù((ÆC¦®….Á£R<9\ñŒe«Ð‚7༰+µ—z/fëÀè×`!+‰et£ui,xŠk8¥Ó#®;PÍELªéð¸v[Kïºw%’5¶“ÂF+ù#O›„-a½wkøu’kmˆ„Pɯ¼ùºY­Ok¾K¥`‡­ðț°á“Ú†‡E¨Ž¢x`¨¬ð Ý¡û2…{åÌ  Y%,¹’*@òÍ*œUOÖ´Îe“}¦ñÒhÂR/”]{µ¹ÓÆRæ+´N©QÖR_á6Ät͒;<·ðÚbK¿ì*”p] +ùi/÷ÜÆ’Í›‡® yd³þ·¿œ×7l~³ \(65ÃÆ±ñGڏ(`ñ!é˜<»æ‡bá™Áøn¥Zü¼_æ0 *мUþ•Z £À¯ÂÊ 9'ƽÃÙèö×Ýd6¡ƒ+Ëxá[Þ{ìýt_‘"endstream +endobj +251 0 obj +601 +endobj +252 0 obj<>>>>>endobj +253 0 obj<>stream +xÚ-‹A‚0D÷ÿ³ÔE+¿EêVEÖ*ß S£E‘ÄëkÕÌ$“¼É{#û„a‹ÔöF+¡Yµ3¤[£œÉ §I¹_V…õa[£î»ñÕ ¥†sLÓá>†>NåBêgª¿Ê&ÁÜzŽ/°Úé>6Ç«O×FhGo³Ó#Ûendstream +endobj +254 0 obj +126 +endobj +255 0 obj<>>>>>endobj +256 0 obj<>stream +xÚ+ä2T0BCs#c3…ä\.§.}7KCK…4 Œ™¹‰BHІ‰‚KjIbfNj +Qœ™ž§’Tg¡`hQ§‹O¡‰¹‰žPPÞÐ$àÂÈe!endstream +endobj +257 0 obj +94 +endobj +258 0 obj<>>>>>endobj +259 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS046Ò3W072PIÑp rt QÐUp VÎO+)O,JUpI-ÎLÏQÉE™%™ùyš!Y\ººP­†& A=#°€ PCIbfNj +Ԑ¼kW ~ö&;endstream +endobj +260 0 obj +126 +endobj +261 0 obj<>>>>>endobj +262 0 obj<>stream +xڝTÛn£0}ç+æqû-)¹=fQ’Fªº¬ Ò¾ºfBÝøBm§Qþ~Ç¡•öR,í +„€9œ9ÇsÌk’à 9Ì'p;®’¯Mr½YB¾„fO•Ù¼€¦ý²‚­4Î1{¾j^À4[ tºÈP–CƒV¹3ƒ<âM'³R¥â“Ò +¸QýÑ£Étwdf¿¥¿Â{f™”(Ç kÔ­Ð 9Š·ðÐ2Ï@‹àŸ™&ãO£¼Pñ†¢Ç˜z£1=±sp¡ŽZpæ…Ñ8µÑ(á ý Qƒ?è­é,S.ÖΡì¿Üýƒ'gø}Ìɽ¸Ò$ßØÃˆ»ìÏT¤”§ôvù‘‹ ¬¸5ú‹Æª.w»ˆE Âidµgºe¶…Ò´{ò¿ÓtUEtO +ª:Œø.«z¼UI‰êña÷*+´K[ŸGá\×åu5Nº®êoŸˆ¿4@ë"̛&»¡±L»=6ã 72ÂvW¥Ûûq¾;­?¡[ËúgÁÜ¿oÊáÓÅut±  ÿõ—(æ…á&òix±n’ïÉOÇ^8Tendstream +endobj +263 0 obj +425 +endobj +264 0 obj<>>>>>endobj +265 0 obj<>stream +xڝ’ÝRÂ0…ïû{©­´@©—ü´# ¢C¨‘’h@}z“ª08ӈN{µgöۜ³ûâ…Ð1_ÝØþt㍰w•ņ€W¶'½ ¼¼¸A>Ï/ñ“Ñ{Gݏâ ×èl_1­}D蚨% Ņf +ÆRh%+˜QnIÉ> ßü„1ûLj™|8?MqÖŸZ”`RQrÁ˜a—€I½†L*êä"t¶y¬e"%µ¤²r‹ÅoD¢¹¤‚B±4aÔ°P%ü½ì9š´³çÆù!Ö a'*Ÿæi;+ßVšoؒ8„^AúJͶ\‘:/ ™5ÿ嬐Ë1’µ.¨âÏúè›ÕMÁc‘Ú©S;CÊY]Ûǎ*I×ΰ㄰â;nVñŠVDÔ+Ã>=£ä«/îè'×Al;'wà ƒã{T@!WzO³þx)~ÚôÃndzýAÔ±­al‹½0 úІACª¤xÛÔVJ±wë}ûì'endstream +endobj +266 0 obj +380 +endobj +267 0 obj<>>>/Annots 117 0 R>>endobj +268 0 obj<>stream +xÚݛÛrÛ6†ïý¼l/Âgâ2±ãԝdâØêÈ2m3Ñ©”œÔ}úâ° ‰õUD7QYò£ø/°‹ÃêïRTæ?R(Z0Y,V'ïg'oÏuAt1»+ˆd%-¤æsvûÛl~³lŠÍ]qºYï›õ~÷ûìÛɇÙIUV†b?ˆý¸úh…dµ¹mUØOÿ÷²¸¶üƒË»ûâí¹(±O´·iÿ4RŒâäª`¢¬S¾·åz±Ù64P*x*æqæ’ròÿȨLZ¥©0Ÿ«BÐR@##5©¿%•Né2£u]™;‰U;~ØèâÖôŠö®]Ì÷ífý¼êB•jJºcÚº7ںƨ¶VQBÍNSŠi +äZ•2%ƒH×O»}³Ê †á~ã Fú/†ƒ·íˏ¦ûÑ6?Ÿw'¥ž„s¯]›—¯øFÎ+Bëz:C¼Ȥ²£"AƒPg›ÅãÊt÷q^Œ0@ÎKžÃ@D\CM:²kH6à Eû€ïÿ~QÀŠùPMó?à…•+á{+P®š»¦k֋f7¢£žVüyæC:¿Q ÷¾ñ²p/¤{oІûð„ڍä Þì9§]^g\6Ük:¿¨¬Ób’·{RK™´!åq†ù„‹!MøF6 qéÃ1EÓD ו‰] Ì@ú²hºŒ;†Ûm–¨l,Ša`XpÈø¢“C,ˆ6¯ Éýý²€D­:æåÏ]OŽùÎ(gÍ®½_£¢ÛÍW­ûï ,o04GL3¶ dôT҇v×£]ã…­R>ê3<¦Á3´°=~˜ô~¾øÞ¬ow£$:=…Çå5i²2Õ¹(¬íèöQyÍBk’æD`v]P¢ÁîPívû¼œ„•“Z„aB*íâ§7×È +YW>œZ))&%°AÊîí¶ÜÞþ?ĔÒMŒýÛ¹FVL©ü4يÉ01M¨í%p°l;ïæËe³|^Q6•xŠI)˜ËþÝ\#+¥àe?Ä9&%° µS¸v€íš®Iízt*]S"bòÊ' +÷v®‘Ó¥S`b›abk;Àv«›‘A.'•€0-©Š2kdµ¤}¸”˜’@&”—:EƒÝ¡v“Í÷#R™82 )e~~ÄMhïW¾‘[]pÂCÞÁV¬Eÿ˜xVԓÞ7Ý÷fÙì2I†6ßȅ]&AGl9p•}%\0;ÎéNjÑ)À”O®°îÉÕ°†òl÷4ÙrCCg`—Ú8ضXÎw»±bVMC]LHƇäY!™9ˆáQØ~žšÀÁ°o››Ý«˜¨bbR¥ ×ȊIiHA šÀö»® ìÛvízßt»ÑÅè4ÖPXÔ¬êa3Ï7²Q³Ò!ÿp,nÙ$d0ée—2eXÖ#wóE“9ç‹ö¨CÀüÔÞtóîiÔËüˆ^F† ÕbXÏùFn˜P ‡£¡;‰f=— Á.ýÊaý£Y·ö|/㐈±*he6b¸À!Ï× {î4¾ãûKW#˜j2¤OßÈz ¦!}r4ê6q«év€ý1›]æÆƒŠ¾(Q6ê%0sÁÀBå?ÒhÀü ë!ûúFÖR—ýXÀF`ÛìËS8Øvq™sCt·Wõá  Ç<‚­w1äoßȺÃ܁í€6áÔFv€}š¯ïç÷¹È! °–62ÅÀp§èÌœËOßÈz‚³>ý£Û§m·õy +;À>_|þ PÃí6@ÑÃo.ÚÄ2ÄË]Au”­©Æ²5«‚#°Ý×@&Я$ho÷¨Ë˳\|î]¹RS’’àÂ|pÌÉ1æ"¢”M–²‰R¶Âl›se +;À®æ»}®>$Ø1Aú/>$mw|Yڶޜؘp«ZÑ¡rÐ7r«Z±·²: äÚnØ&d0é¼]Ž/ò¨šìÞÒËI­‡ ì¹^Nt(²)º8lâ6"¸·ØÃö~¹ßlÇVÐbâbJ*9dPßÈ*©úNñÛÎ3ªv€µ+3‘—’³ lFhDG•½øFVGÙ÷Gl‚Èþð1AƒÝïçìÆ¤j2Ûc˜Œ<*zñ¬Œ¢/zèÔ:°mÙºLáÞ`ûæŸ}f`OekLç“arH>¾‘K>„õ%/I>¬å!Ì@º^<4·Ë¦{MåmX¥Qõ‹od;(í«_$žy€mwõt +;ÀÞ=î6]ûo®„¹:ê¹6¦"‰Ê^|#«"éË^$žu€m×Up°ì4{.3ýQî”ÔQ͋ÆJ^tDĒŽ/6èÃzÏ9]¶Íz¬Ü…Ogj‰(X³!ãÔ I8u_ì"Ñ|`»&²·öå)ë»öþ±Ëe:ݱ¬¢ê…§¨¾6E¢0&&O¨„ì­@:k»f±ßtO¹°ž`W›µ ®1ÌÀ»¶5ï£?èqk‚_î +Rå] ¢’U´ˆzÈHØÖ € ¡îgPù(../_C‘0¦"çq)&V‰)†Œ¤ÐBL¨c±q—–±ҟã§Û“©bÁ$ddÈFŒ وõÖØ¡6lT…g¤GÚnvÞ®G끧RSåõ{{^ïJˆí ²ö?ƒºzw>+Þî@ùzs·ÿ9ïš~Ðcþ·èÚmÈLØßξQÔ½V ê}=ù41ž×endstream +endobj +269 0 obj +2170 +endobj +270 0 obj<>>>/Annots 149 0 R>>endobj +271 0 obj<>stream +xÚ՘Ms›0†ïþ:¶‡(è8ºIkšÐÞ)&2`»ÀL'ÿ¾+i1à‰Dn¦q{gÑ+ô¬V+ñgÃHF„6ÿE³ù–mnw)a)É^ӂr¢c×lÿ%Ë×%9¾»ã¡/}÷5{Û|Ï6@Å\˜¹<=˜Óˆh‘@»†¤š&hÔäÙôpÑ }%·;I3}ÆÐ¡H]‡‚jšo/á†0ÁÎ}b7èG±Ç¶‚§níCZ>€à4p½æ‹¼£ڌ+¸6DqªÐð2…€j®ÇØOq"Ր$¦z®‹n«óüÞõe㗚´†°'TÌ¥Ðm¥~Â:6„°Êär¤è·2wǦÉ{OPe|å ÂéR„1˜¢CŠXÃN“ŒÃ. ”-%j3./ÅяbyQ”§þc‚<†ä¹~Z,“T0+ô@Ò!’*Mé0Â0ÉAۑœ‰£ŊüP”õÿN2QTžIZ#H2Ñp’K$Q›t.Ž~ÛW)6žµ:ZÈEŽp=—?g9Æb(z10XàˆÚ ÖE5G?Š•?FnⵊÉHªÔU;4kIêhਖ8¢2‹°˜I;¿“ªOLVï³¥k3‚¥k^âˆÚLðKqô£X}Ê÷Muð䵙ÌW'ºÈÆ8Vk9 +1Všx‰#j3Á÷Lý(VŸº>÷Õl¶Š­ì§X²tRk¬d Xε&Yb‰Ú xð¹¸óbmùV~–ÉúY‚Ad*Üë~[ +[¦™e(8£ ;"ØvÎԝ×jܗ}^Õå>pԛÃ2Ø̴Ѝb]õêY'x +-W´òŽ!áií²;‚u†7FæîØåúÖt¢dτ|.‹nÔy¨]—·ïžÅ7¥l•P§|Uøt,•°)¯¤™ZÖøÄ8'Kha§Ý6t¬šÈÂôç‡éëܨ”•mÓy7^ÉQ/║ÝuºZ#ôòAJæ6¡ÛÐ k"f2#43iôRE{<¼ûÀJ¹’íÒÛ]2Ì5['n7tÿ´Ýeä†Üý||&ÏǗþoޖÄ-}æ«h«S_í2xÃì+ª›˜ÛVý±ùõÖñfendstream +endobj +272 0 obj +837 +endobj +273 0 obj<>endobj +274 0 obj<>endobj +275 0 obj<>endobj +276 0 obj<>endobj +277 0 obj<>endobj +278 0 obj<>endobj +279 0 obj<>endobj +280 0 obj<>endobj +281 0 obj<>endobj +282 0 obj<>endobj +283 0 obj<>endobj +284 0 obj<>endobj +285 0 obj<>endobj +286 0 obj<>endobj +287 0 obj<>endobj +288 0 obj<>endobj +289 0 obj<>endobj +290 0 obj<>endobj +291 0 obj<>endobj +292 0 obj<>endobj +293 0 obj<>endobj +294 0 obj<>endobj +295 0 obj<>endobj +296 0 obj<>endobj +297 0 obj<>endobj +298 0 obj<>endobj +299 0 obj<>endobj +300 0 obj<>endobj +301 0 obj<>endobj +302 0 obj<>endobj +303 0 obj<>endobj +304 0 obj<>endobj +305 0 obj<>endobj +306 0 obj<>endobj +307 0 obj<>endobj +308 0 obj<>endobj +309 0 obj<>endobj +310 0 obj<>endobj +311 0 obj<>endobj +312 0 obj<>endobj +313 0 obj<>endobj +314 0 obj<>endobj +315 0 obj<>endobj +316 0 obj<>endobj +317 0 obj<>endobj +318 0 obj<>endobj +319 0 obj<>endobj +320 0 obj<>endobj +321 0 obj<>endobj +322 0 obj<>endobj +323 0 obj<>endobj +324 0 obj<>endobj +325 0 obj<>endobj +326 0 obj<>endobj +327 0 obj<>endobj +328 0 obj<>endobj +329 0 obj<>endobj +330 0 obj<>endobj +331 0 obj<>endobj +332 0 obj<>endobj +333 0 obj<>endobj +334 0 obj<>/Outlines 273 0 R/PageMode/UseOutlines/OpenAction[219 0 R/XYZ null null null]>>endobj +xref +0 335 +0000000000 65535 f +0000000015 00000 n +0000000224 00000 n +0000000285 00000 n +0000000359 00000 n +0000000441 00000 n +0000000519 00000 n +0000000596 00000 n +0000000675 00000 n +0000000751 00000 n +0000000832 00000 n +0000000891 00000 n +0000000994 00000 n +0000001098 00000 n +0000001203 00000 n +0000001308 00000 n +0000001413 00000 n +0000001518 00000 n +0000001623 00000 n +0000001728 00000 n +0000001833 00000 n +0000001938 00000 n +0000002041 00000 n +0000002145 00000 n +0000002250 00000 n +0000002355 00000 n +0000002460 00000 n +0000002565 00000 n +0000002670 00000 n +0000002775 00000 n +0000002878 00000 n +0000002982 00000 n +0000003087 00000 n +0000003192 00000 n +0000003297 00000 n +0000003402 00000 n +0000003507 00000 n +0000003612 00000 n +0000003717 00000 n +0000003822 00000 n +0000003927 00000 n +0000004032 00000 n +0000004137 00000 n +0000004242 00000 n +0000004347 00000 n +0000004452 00000 n +0000004557 00000 n +0000004662 00000 n +0000004767 00000 n +0000004872 00000 n +0000004977 00000 n +0000005082 00000 n +0000005187 00000 n +0000005292 00000 n +0000005397 00000 n +0000005502 00000 n +0000005607 00000 n +0000005712 00000 n +0000005817 00000 n +0000005922 00000 n +0000006027 00000 n +0000006132 00000 n +0000006237 00000 n +0000006342 00000 n +0000006447 00000 n +0000006552 00000 n +0000006657 00000 n +0000006762 00000 n +0000006867 00000 n +0000006972 00000 n +0000007077 00000 n +0000007182 00000 n +0000007287 00000 n +0000007392 00000 n +0000007497 00000 n +0000007602 00000 n +0000007707 00000 n +0000007812 00000 n +0000007917 00000 n +0000008022 00000 n +0000008127 00000 n +0000008232 00000 n +0000008337 00000 n +0000008442 00000 n +0000008547 00000 n +0000008652 00000 n +0000008757 00000 n +0000008862 00000 n +0000008967 00000 n +0000009072 00000 n +0000009177 00000 n +0000009282 00000 n +0000009387 00000 n +0000009492 00000 n +0000009597 00000 n +0000009702 00000 n +0000009807 00000 n +0000009912 00000 n +0000010017 00000 n +0000010122 00000 n +0000010227 00000 n +0000010333 00000 n +0000010439 00000 n +0000010545 00000 n +0000010651 00000 n +0000010757 00000 n +0000010863 00000 n +0000010969 00000 n +0000011075 00000 n +0000011181 00000 n +0000011287 00000 n +0000011393 00000 n +0000011498 00000 n +0000011603 00000 n +0000011707 00000 n +0000011811 00000 n +0000011915 00000 n +0000012019 00000 n +0000012796 00000 n +0000012902 00000 n +0000013008 00000 n +0000013112 00000 n +0000013217 00000 n +0000013323 00000 n +0000013429 00000 n +0000013535 00000 n +0000013641 00000 n +0000013747 00000 n +0000013853 00000 n +0000013959 00000 n +0000014065 00000 n +0000014171 00000 n +0000014277 00000 n +0000014383 00000 n +0000014489 00000 n +0000014595 00000 n +0000014701 00000 n +0000014807 00000 n +0000014913 00000 n +0000015019 00000 n +0000015125 00000 n +0000015229 00000 n +0000015333 00000 n +0000015438 00000 n +0000015542 00000 n +0000015646 00000 n +0000015750 00000 n +0000015855 00000 n +0000015959 00000 n +0000016064 00000 n +0000016330 00000 n +0000016364 00000 n +0000016398 00000 n +0000017221 00000 n +0000017270 00000 n +0000017319 00000 n +0000017368 00000 n +0000017417 00000 n +0000017466 00000 n +0000017515 00000 n +0000017564 00000 n +0000017613 00000 n +0000017662 00000 n +0000017711 00000 n +0000017760 00000 n +0000017809 00000 n +0000017858 00000 n +0000017907 00000 n +0000017956 00000 n +0000018005 00000 n +0000018054 00000 n +0000018103 00000 n +0000018152 00000 n +0000018201 00000 n +0000018250 00000 n +0000018299 00000 n +0000018348 00000 n +0000018397 00000 n +0000018446 00000 n +0000018495 00000 n +0000018544 00000 n +0000018593 00000 n +0000018642 00000 n +0000018691 00000 n +0000018740 00000 n +0000018789 00000 n +0000018838 00000 n +0000018887 00000 n +0000018936 00000 n +0000018985 00000 n +0000019034 00000 n +0000019083 00000 n +0000019132 00000 n +0000019181 00000 n +0000019230 00000 n +0000019279 00000 n +0000019328 00000 n +0000019377 00000 n +0000019426 00000 n +0000019475 00000 n +0000019524 00000 n +0000019573 00000 n +0000019622 00000 n +0000019671 00000 n +0000019720 00000 n +0000019769 00000 n +0000019818 00000 n +0000019867 00000 n +0000019916 00000 n +0000019965 00000 n +0000020014 00000 n +0000020063 00000 n +0000020112 00000 n +0000020341 00000 n +0000020493 00000 n +0000026875 00000 n +0000026897 00000 n +0000027010 00000 n +0000027112 00000 n +0000027132 00000 n +0000027273 00000 n +0000028169 00000 n +0000028190 00000 n +0000028303 00000 n +0000028495 00000 n +0000028516 00000 n +0000028657 00000 n +0000029250 00000 n +0000029271 00000 n +0000029384 00000 n +0000029580 00000 n +0000029601 00000 n +0000029751 00000 n +0000030764 00000 n +0000030785 00000 n +0000030944 00000 n +0000032099 00000 n +0000032121 00000 n +0000032252 00000 n +0000033131 00000 n +0000033152 00000 n +0000033293 00000 n +0000034403 00000 n +0000034425 00000 n +0000034556 00000 n +0000035538 00000 n +0000035559 00000 n +0000035699 00000 n +0000036690 00000 n +0000036711 00000 n +0000036842 00000 n +0000037514 00000 n +0000037535 00000 n +0000037648 00000 n +0000037845 00000 n +0000037866 00000 n +0000037988 00000 n +0000038153 00000 n +0000038173 00000 n +0000038286 00000 n +0000038483 00000 n +0000038504 00000 n +0000038644 00000 n +0000039140 00000 n +0000039161 00000 n +0000039292 00000 n +0000039743 00000 n +0000039764 00000 n +0000039919 00000 n +0000042160 00000 n +0000042182 00000 n +0000042337 00000 n +0000043245 00000 n +0000043266 00000 n +0000043321 00000 n +0000043426 00000 n +0000043570 00000 n +0000043676 00000 n +0000043796 00000 n +0000043905 00000 n +0000044054 00000 n +0000044164 00000 n +0000044271 00000 n +0000044425 00000 n +0000044561 00000 n +0000044658 00000 n +0000044768 00000 n +0000044883 00000 n +0000044996 00000 n +0000045106 00000 n +0000045206 00000 n +0000045364 00000 n +0000045461 00000 n +0000045571 00000 n +0000045669 00000 n +0000045813 00000 n +0000045914 00000 n +0000046025 00000 n +0000046127 00000 n +0000046290 00000 n +0000046405 00000 n +0000046526 00000 n +0000046646 00000 n +0000046771 00000 n +0000046892 00000 n +0000047012 00000 n +0000047122 00000 n +0000047270 00000 n +0000047372 00000 n +0000047488 00000 n +0000047601 00000 n +0000047703 00000 n +0000047853 00000 n +0000047960 00000 n +0000048074 00000 n +0000048187 00000 n +0000048307 00000 n +0000048432 00000 n +0000048542 00000 n +0000048653 00000 n +0000048764 00000 n +0000048866 00000 n +0000049011 00000 n +0000049111 00000 n +0000049224 00000 n +0000049338 00000 n +0000049451 00000 n +0000049560 00000 n +0000049674 00000 n +0000049787 00000 n +0000049887 00000 n +0000050005 00000 n +0000050139 00000 n +0000050236 00000 n +0000050336 00000 n +trailer +<> +startxref +50522 +%%EOF diff --git a/doc/sdd.shtml b/doc/sdd.shtml new file mode 100644 index 0000000000..9d8d59d30a --- /dev/null +++ b/doc/sdd.shtml @@ -0,0 +1,567 @@ + + + + + + DRAFT - CUPS Software Design Description + + + +

Scope

+ +

Identification

+ +This software design description document provides detailed information +on the architecture and coding of the Common UNIX Printing System +("CUPS") Version 1.0. + +

System Overview

+ +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +This software design description document is organized into the +following sections: + +
    + +
  • 1 - Scope + +
  • 2 - References + +
  • 3 - Design Overview + +
  • 4 - Detailed Design + +
  • A - Glossary + +
+ +

References

+ +

CUPS Documentation

+ +The following CUPS documentation is referenced by this document: + +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan +
  • CUPS-IDD-1.0: CUPS System Interface Design Description +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual +
  • CUPS-SDD-1.0: CUPS Software Design Description +
  • CUPS-SPM-1.0: CUPS Software Programming Manual +
  • CUPS-SSR-1.0: CUPS Software Security Report +
  • CUPS-STP-1.0: CUPS Software Test Plan +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual +
  • CUPS-SVD-1.0.x: CUPS Software Version Description +
+ +

Other Documents

+ +The following non-CUPS documents are referenced by this document: + +
    +
  • IEEE 1387.4, System Administration: Printing (draft) +
  • IPP/1.0: Additional Optional Operations - Set 1 +
  • IPP/1.0: Encoding and Transport +
  • IPP/1.0: Implementers Guide +
  • IPP/1.0: Model and Semantics +
  • RFC 1179, Line Printer Daemon Protocol +
+ +

Design Overview

+ +CUPS is composed of 7 software sub-systems that operate together to +perform common printing tasks: + +
    + +
  • Backends + +
  • Berkeley Commands + +
  • CGI + +
  • CUPS Interface Library + +
  • Filters + +
  • Scheduler + +
  • System V Commands + +
+ +

Backends

+ +The backends implement communications over a number of different interfaces. +All backends are called with a common set of arguments: + +
    + +
  • Device URI - the Uniform Resource Identifier for the output device + (e.g. parallel:/dev/plp, + ipp://hostname/resource). + +
  • Job Identifier - the job identifier for this job (integer). + +
  • User Name - the user associated with this job (name string). + +
  • Title - the title/job-name associated with this job (name string). + +
  • Copies - the number of copies required (integer). + +
  • Options - the options associated with this job (space separated + option strings). + +
  • Filename (optional) - the file to print; if this option is not + specified, the backend must read the print file from the standard + input. + +
+ +Backends are named using the method of the URI, so a URI of +"ipp://hostname/resource" would be processed by the "ipp" backend. + +

ipp

+ +The ipp backend sends the specified job to a network printer or host using +the Internet Printing Protocol. The URI is as specified by the +printer-uri-supported attribute from the printer or host. + +

lpd

+ +The lpd backend sends the specified job to a network printer or host using +the Line Printer Daemon protocol. The URI is of the form: + +
    lpd://hostname/queue
    +
+ +

parallel

+ +The parallel backend sends the specified job to a local printer connected +via the specified parallel port device. The URI is of the form: + +
    parallel:/dev/file
    +
+ +

serial

+ +The serial backend sends the specified job to a local printer connected +via the specified serial port device. The URI is of the form: + +
    serial:/dev/file?option[+option+...]
    +
+ +The options can be any combination of the following: + +
    + +
  • baud=rate - Sets the baud rate for the device. + +
  • bits=7 or 8 - Sets the number of data bits. + +
  • parity=even - Sets even parity checking. + +
  • parity=odd - Sets odd parity checking. + +
  • parity=none - Turns parity checking off. + +
+ +

smb

+ +The smb backend sends the specified job to a network host using the Server +Message Block protocol, which is used by most machines running Microsoft® +Windows®. The URI is of the form: + +
    smb://hostname/queue
    +
+ +Usernames and passwords required to access the printer are stored in an +external file. + +

socket

+ +The socket backend sends the specified job to a network host using the +AppSocket protocol commonly used by Hewlett-Packard and Tektronix +printers. The URI is of the form: + +
    socket://hostname[:port]
    +
+ +The default port number is 9100. + +

Berkeley Commands

+ +The Berkeley commands provide a simple command-line interface to CUPS +to submit and control print jobs. It is provided for compatibility with +existing software that is hard coded to use the Berkeley commands, +however since printer options cannot be specified using the Berkeley +commands their use it not encouraged. + +

lpc

+ +The lpc command allows users and administrators to check the status and +control print queues. The version provided with CUPS supports the following +commands: + +
    + +
  • abort - Stops a printer or all printers and any active print jobs. + +
  • disable - Prevents new jobs from being submitted to the specified + printer or all printers. + +
  • down - Stops a printer or all printers after completing the current + print jobs. + +
  • enable - Allows new jobs to be submitted. + +
  • start - Starts a printer or all printers. + +
  • status - Shows the status of printers and jobs in the queue. + +
  • up - Starts a printer or all printers. + +
+ +

lpr

+ +The lpr command submits a job for printing. The CUPS version of lpr silently +ignores the "i", "p", "t", "m", "h", and "s" options. + +

lprm

+ +The lprm removes one or more print jobs. + +

CGI

+ +The Common Gateway Interface (CGI) programs provide a web-based status interface +to monitor the status of printers, classes, and jobs. + +

classes

+ +The classes CGI lists the available printer classes and any pending jobs for +the class. The user can click on individual classes to limit the display and +click on jobs to see the job status. + +

jobs

+ +The jobs CGI lists the queued print jobs in order of priority. The list can +be limited by printer or job. When the user displays the status of an +individual print job all job options are displayed. + +

printers

+ +The printers CGI lists the available printer queues and any pending jobs for +the printer. The user can click on individual printers to limit the display and +click on jobs to see the job status. + +

CUPS Interface Library

+ +The CUPS interface library provides common convenience, HTTP, IPP, +language, MIME, PPD, and raster functions used by the CUPS software. + +

Convenience Functions

+ +Convenience functions are provided to submit an IPP request, send a print file, +cancel a job, get a list of available printers, and get a list of available +classes. + +

HTTP Functions

+ +The HTTP functions provide functions to connect to HTTP servers, issue requests, +read data from a server, and write data to a server. + +

IPP Functions

+ +The IPP function provide functions to manage IPP request data and attributes, +read IPP responses from a server, and write IPP requests to a server. + +

Language Functions

+ +The language functions provide a standard interface for retrieving common +textual messages for a particular locale and determining the correct encoding +(e.g. US ASCII, ISO-8859-1, etc.) + +

MIME Functions

+ +The Multimedia Internet Mail Exchange functions manage a MIME type and +conversion database that supports file typing by extension and content, and +least-cost file filtering from a source to a destination file type. + +

PPD Functions

+ +The PostScript Printer Description functions manage PPD files, select options, +check for option conflicts, and emit selected options in the correct order. + +

Raster Functions

+ +The raster functions manage streams of CUPS raster data (described in the +Interface Design Document) used by non-PostScript printer drivers. + +

Filters

+ +The filters implement file conversion services for CUPS. All filters +are called with a common set of arguments: + +
    + +
  • Printer name - the name of the destination printer (name string). + +
  • Job Identifier - the job identifier for this job (integer). + +
  • User Name - the user associated with this job (name string). + +
  • Title - the title/job-name associated with this job (name string). + +
  • Copies - the number of copies required (integer). + +
  • Options - the options associated with this job (space separated + option strings). + +
  • Filename (optional) - the file to print; if this option is not + specified, the filter must read the input file from the standard + input. + +
+ +Filters are added to the MIME conversion data file and implement all necessary +conversions from one file type to another. + +

hpgltops

+ +The hpgltops filter converts HP-GL/2 files into PostScript. + +

imagetops

+ +The imagetops filter converts image files into PostScript. + +

pstops

+ +The pstops filter inserts printer-specific commands from PPD files and +performs page filtering as requested by the user. + +

texttops

+ +The texttops filter converts text files into PostScript. + +

Scheduler

+ +The scheduler is a fully-functional HTTP/1.1 server that manages the printers, +classes, and jobs in the system. It also handles a simple broadcast-based +directory service so that remote print queues and classes can be accessed +transparently from the local system. + +

Authorization

+ +The authorization module is responsible for performing access control and +authentication for all HTTP and IPP requests entering the system. + +

Classes

+ +The classes module is responsible for managing printer classes in the system. +Each class is a collection of local and/or remote printers. The classes module +also reads and writes the classes configuration file. + +

Client

+ +The client module is responsible for all HTTP client communications. It handles +listening on selected interfaces, accepting connections from prospective +clients, processing incoming HTTP requests, and sending HTTP responses to +those requests. The client module also is responsible for executing the +external CGI programs as needed to support web-based printer, class, and job +status monitoring. + +

Once authorized, all IPP requests are sent to the IPP module. + +

Configuration

+ +The configuration module is responsible for reading the CUPS configuration file +and initializing the appropriate data structures and values. The configuration +module also stops CUPS services before reading the configuration file and +restarts them after the configuration file has been read. + +

Directory Services

+ +The directory services module sends and recieves printer state information over +a broadcast socket. Remote printers and classes are automatically added to or +removed from the local printer and class lists as needed. + +

The directory services module can only recieve printer state information +over a single UDP port, however it can broadcast to multiple addresses and +ports as needed. + +

IPP

+ +The IPP module handles IPP requests and acts accordingly. URI +validation is also performed here, as a client can post IPP data to any +URI on the server (which might sidestep the access control or +authentication of the HTTP server.) + +

Jobs

+ +The jobs module manages print jobs, starts filter and backend processes +for jobs to be printed, and monitors status messages from those filters +and backends. + +

Main

+ +The main module is responsible for timing out and dispatching input and output +for client connections. It also watches for incoming SIGHUP +signals and reloads the server configuration files as needed. + +

Printers

+ +The printers module is responsible for managing printers and PPD files +in the system. The printers module also reads and writes the printers +configuration file. + +

System V Commands

+ +The System V commands provide a robust command-line interface to CUPS +to submit and control print jobs. + +

accept

+ +The accept command tells the scheduler to accept new jobs for specific +printers. + +

cancel

+ +The cancel command tells the scheduler to cancel one or more jobs that are +queued for printing. + +

disable

+ +The disable command tells the scheduler to stop printing jobs on the +specified printers. + +

enable

+ +The enable command tells the scheduler to start printing jobs on the +specified printers. + +

lp

+ +The lp command submits submits files for printing. Unlike the standard +System V lp command, a single CUPS lp command will generate a separate +job ID for each file that is printed. Also, the Solaris "f", "H", "P", "S", +and "y" options are silently ignored. + +

lpadmin

+ +The lpadmin command manages printer queues and classes. The Solaris +"A", "F", "I", "M", "P", "Q", "S", "T", "U", "W", "f", "l", "m", "o", +"s", "t", and "u" options are not supported, and new options "P" (PPD +file) and "F" (filter) are provided to configure CUPS-specific features +such as PPD file and conversion filters. + +

lpstat

+ +The lpstat command lists printers, classes, and jobs as requested by the +user. + +

reject

+ +The reject command tells the scheduler not to accept new jobs for specific +printers. + +

Detailed Design

+ +

Glossary

+ +

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. + +
+ +

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 Printer 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 + +
PCL +
Page Control Language + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
+ + + diff --git a/doc/ssr.html b/doc/ssr.html new file mode 100644 index 0000000000..51be5b88e5 --- /dev/null +++ b/doc/ssr.html @@ -0,0 +1,221 @@ + + +DRAFT - CUPS Software Security Report + + + + + +

+

DRAFT - CUPS Software Security Report


+CUPS-SSR-1.0
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Local Access Risks + +4 Remote Access Risks + +A Glossary + +
+

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.0. +

1.2 System Overview

+ The Common UNIX Printing System provides a portable printing layer for + UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

1.3 Document Overview

+

This software security report is organized into the following +sections:

+
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Local Access Risks
  • +
  • 4 - Remote Access Risks
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+ The following CUPS documentation is referenced by this document: +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.0: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.0: CUPS Software Design Description
  • +
  • CUPS-SPM-1.0: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.0: CUPS Software Security Report
  • +
  • CUPS-STP-1.0: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.0.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+ The following non-CUPS documents are referenced by this document: +
    +
  • IEEE 1387.4, System Administration: Printing (draft)
  • +
  • IPP/1.0: Additional Optional Operations - Set 1
  • +
  • IPP/1.0: Encoding and Transport
  • +
  • IPP/1.0: Implementers Guide
  • +
  • IPP/1.0: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
+

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.

+

3.1 Security Breaches

+

Since the default installation creates a world-readable request +directory, it is possible for local users to read the contents of print +files before they are printed.

+

This problem can be alleviated by making the request directory +readable only by the user specified in the CUPS configuration file.

+

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.

+

4.1 Denial of Service Attacks

+

Like all internet services, the CUPS server is vulnerable to denial +of service attacks, including:

+
    +
  1. 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 determined attack.

    +
  2. +
  3. 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.

    +
  4. +
  5. 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.

    +
  6. +
  7. 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.

    +
  8. +
  9. 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.

    +
  10. +
+

4.2 Security Breaches

+

The current CUPS server only supports Basic authentication with +usernames and passwords. This 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.

+

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.

+

The next minor release of CUPS will support Digest authentication of +the entire message body using separate MD5-based username and password +files. This will protect password information and prevent unauthorized +access due to compromised account passwords.

+

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.
+
+

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 Printer 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
+
PCL
+
Page Control Language
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/ssr.pdf b/doc/ssr.pdf new file mode 100644 index 0000000000..8ae80cf93e --- /dev/null +++ b/doc/ssr.pdf @@ -0,0 +1,446 @@ +%PDF-1.2 +%âãÏÓ +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +4 0 obj<>endobj +5 0 obj<>endobj +6 0 obj<>endobj +7 0 obj<>endobj +8 0 obj<>endobj +9 0 obj<>endobj +10 0 obj<>endobj +11 0 obj<>endobj +12 0 obj<>endobj +13 0 obj<>endobj +14 0 obj<>endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj<>endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj<>endobj +22 0 obj<>endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj<>endobj +26 0 obj<>endobj +27 0 obj<>endobj +28 0 obj<>endobj +29 0 obj<>endobj +30 0 obj<>endobj +31 0 obj<>endobj +32 0 obj<>endobj +33 0 obj<>endobj +34 0 obj<>endobj +35 0 obj<>endobj +36 0 obj<>endobj +37 0 obj<>endobj +38 0 obj<>endobj +39 0 obj<>endobj +40 0 obj<>endobj +41 0 obj<>endobj +42 0 obj<>endobj +43 0 obj<>endobj +44 0 obj<>endobj +45 0 obj<>endobj +46 0 obj<>endobj +47 0 obj<>endobj +48 0 obj<>endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj<>endobj +52 0 obj<>endobj +53 0 obj[10 0 R +11 0 R +12 0 R +13 0 R +14 0 R +15 0 R +16 0 R +17 0 R +18 0 R +19 0 R +20 0 R +21 0 R +22 0 R +23 0 R +24 0 R +25 0 R +26 0 R +27 0 R +28 0 R +29 0 R +30 0 R +31 0 R +32 0 R +33 0 R +34 0 R +35 0 R +36 0 R +37 0 R +38 0 R +39 0 R +40 0 R +41 0 R +42 0 R +43 0 R +44 0 R +45 0 R +46 0 R +47 0 R +48 0 R +49 0 R +50 0 R +51 0 R +52 0 R +]endobj +54 0 obj<>endobj +55 0 obj<>endobj +56 0 obj<>endobj +57 0 obj<>endobj +58 0 obj<>endobj +59 0 obj<>endobj +60 0 obj<>endobj +61 0 obj<>endobj +62 0 obj<>endobj +63 0 obj<>endobj +64 0 obj<>endobj +65 0 obj<>endobj +66 0 obj<>endobj +67 0 obj<>endobj +68 0 obj<>endobj +69 0 obj<>endobj +70 0 obj<>endobj +71 0 obj<>endobj +72 0 obj<>endobj +73 0 obj<>>>>>endobj +74 0 obj<>stream +xÚíßÜ8rÇ%µúÅOšÙíwNH€ØîO{Ï@pgF›ì[I¢‡ ‡]_r‡ öÎë½`ÿûô¯éÖRª*R57<à°¶Én~ÄⷊdQý·W7b½ýߍøîV¼ÿ ~üßW÷òU"_ýM¼_ÿîíwû|ÿáÃÛµøÝÇ··âööæíݾÖïòÿ|÷ûìßîÅæ_×ûò~_>ìËÇ}yؗï÷å÷ÿõîñõ˯Ÿßý‡¸{óîßÅæææÝ=<ˆ;ñÃã«âyxá2+òñv¹\^]ìÊö?–wSç’ˋÈS•‹ËëÇirÉÛ+5R ny71.yÛÅôT.¯“©pᡎhwSàz¸òÈÅ_&ŽsÝG¯\næºåRÙ4Gpf¬ìŽ™e®ᙗoǸò+ÏJñ¯âºõ¬•`㠗žÍrí—±^Ø2K\òʳ^ü×£så‘×Gùfd®{¯§$crÝx½3—e´ncmËëQ¸däy.‚“BX-ßÎ5 &€Åƒ)`1ÀÀiÉà‹LËóVqõî·Ì4›k`¬-X2×Ú¼p}òF(³Þ¹2o”òmÏ\y4AÁ}…giLA +ÚÑ ê£såÞ¨eÓW4.rŠÁ2NjÁ4<Yì‰\r|,ÏïK8Àå…Ö¹2ω²±Ì%#7¸Ë\kϑ²°Ê•yΔÄ"—+Vˆrb®Øs¨l¬qå.auJLO4PQLP40QL*ÒÀk=–+u «cÀ`z0˜ Æcœ3ŽKºˆÕ×Ã51Ã`z.5Ã`¸áº¸\._?îÊýîâC¿ƒ —ùº9Éw÷ z0è¸ü–¤ùpÕπAßÃuÙ¹Tº7@[p­ûªò¨-­‡õÐãpҏ%77xÃæb‡´tq&ٌËÅ 5èé¹9kɐ0¹˜ÃÅJ§æ YÈäbòÜlHƐù<®´m·8d+W4” ž¼YdEêÁþ®†IÚ;'Ù`ÃàƒM-~æUHçÊGÀ"ƒùt.²Èûv®H +cåhç ‹6£r¥#!Ç"— ‹¶ qåV<$,2ra`oáõmaµdF†Ö"yËX¤ÛW +Wj!œ1*kƒ/Kªá'ö¹=Hð\Ò@peüÀl¼Kº¹bWDƒ2`«n®È'õ'ìäÊÜ.䀝\±cÅôaIWäØp!Ÿô¢ƒ+wÆ%Óºvp¥Î .J :¸„c³ -eI+—tp¸ps~Õʕ98\¸m¤°• ©òþ X(+ +Z¹"‡"C¢r´qaU~`,ÔôØ´p!U>š« ÙpU~38Âg-\ì­± 1Ðse.ŠÜhKÎôZ!¹VZ®¼ô|k†˜Yª¹€è¼Ú¹B-×Áö‚ó –”>Ps ¢ójç +ô\g­”Uú™#8\a¹žŒKÁuÖö o†¥OT\95†êàZh¹Î"SöJRìCúÚ+ÄsÍô\ñÓ#Š(‹ï+ˆ@^kWBù.Oϕ?+§˜!b¢„*®ˆh†\+-×á»æ‡¿ÂoÙu +ÛLÁ%©fØÉê¹Ö ѕÃdu«;š÷‹IÀÊ|0I.Á‹¢œçŠxQ”ë\ÒDæÊ åÐU®Œ:Ε>79e´ÝÕH³É8·¼Bp÷mê“3Qr-8\ 5Wy&}{âl÷¥Æ×¨N­‹3×Lɕ«Ï—#¶ûRh̸ÖEÃå)¹„ú܁¿i£¶W]nj­‹+×JÁ•6UPn9ÀrÍ4áËJÅr¸BWÔ|Œ–¹«Ë«u1àpM®'Ñð/¢“ÝÊ-‡h®•šËWqÕ¯ó¡¸wOr¾ó'ÑÑlp\óV®ý=¯ÒƒyÕ±$*®…ÒUãQD£²“y:lT¸±èæ:¾Ö8uøäU®”»8ãp5epü:@mb¯\¥´”êŸs{ê]ô8\FÕC§c Â¨ †ëœF¤È’Ÿ+»¸âpÕ‰j`¾§ ¡ \žmç’®XÏr¸êj3eo– Â¨Ãuþƒ"û_Íås¸jêO%žËïƒKq¯›KÑ(«;Øå¶\&< ̹šº¡¸Î×Í¥»ªÖ˞.©áZ«u^qÁÕl+,`¨°0ÑÃè”s[íbó:‚«ÙH(ŠkŽâÊÔþ+ÓÄQŠë|®f#-Wf‰+VÆç0¤ÖÅæu>W³Q¤tD(®†Kz En]§(®óa¸´\)?Œ*õáø+ôºRqÃÕhT®~þFצ0\-”]l\çÃp5i¹€FêÑìª6ºxmW½‘Wæ +Uë'š.Ö¯ó¡¸ê´\±E®zuë×ùP\õFZ®5?<,Ô§ÙÞot±~ÅUoÕÒTO\—Ÿh¸J¡j¥‹µë|8®Z#>W€äòW¥¿=úåã¶ÇBÝÅÚu>W­‘()v…+²ÃUÊ?,LJmPÝÅÚu>W­Q#ŽJ±\a[§*®Òû¡]܋6•«Úh]ˆâ#—×/WÖÆU½Î‡äRÜ,wqåšqåºxþT +"WµQZŸ*сKöÌ%5·8×ù\ÕFYM²¥‡åZq­\Àáª4’µÐÿð›óûç;¹¦’+Ëw¡{›mr¹½.ñÂõÂ5®Ù3å +§É½p½p½p½p½pá¸æ/\/\ýsyæ\ەú^)¥î¸\÷ûw˜ùטîRêŽÌuU¿¾V}ÙPé sŠºêÓõI•§¸(¥í1—h¤oTóôËÇSͺ ®Mu3´'®OÍMõe^ùù°ãæFU'תú@ûᒊ¥ê ÓÓ¿DÝ<êäZ Áª¥µ(O°ZúF­.ƒk^T¦f?\‘ê¨ Êó ª¤ÉÔë2¸Âª¥ô•?<]”ë–_]{>­WÖep•¯î‡+=ʛҗ–$ðœ]¡¬ËçÊúäŠK'Öë³w)¹¬sò¹¦®j›_ý­Õ㝴O.QyžUg ,½YS—ÆåŸŽO·“8è+*oɚҟ'i©Kã +N#îâ2‰ç+ÿ gµ8M°¬š¤­ªK⚝ÇöɄÃp¥ç?R` š¤­ªKâ +ˏnnÆÕ‘~xúçüb[%±JJw¤ôuI\»û_§Ç´è•+ÐýΧ”TܶՏçÇIº›Â«Þ¸"]:ÎñL9/ÁD-©;x®õñóvŸ¼éë n4qcP™FÚº$®ø(C;KOzã:žu^nÔÖ>“âIεuI\pÎ~õ‹Þ¸N!z£·‡~ˆJ¾X_WÉÕLìÜS¤Çùºs_ýq•òAj½Ÿ¼ÍÉëëR¸²£¬wlÆÕv®W®Wy/qÚÌ¢ÕÖ¥påÇ?îܲ!WÛ9l¬¼ÇQY'u)\Ò;½}ÞÎet¾,µ™¥¢‘Õ¢¯Kà*ŽŽyÿ·ýqÕ²hý¤1’!¢.…ëà˜÷n¹O®Ò‹¶ªª™ÓÕ¥ps¶÷ñ}r=]„mäR©’M[ë⸎9Û×7ãêÌûºT³F(Šº.Þ/ïÝ`²û¿ƒËF>ÛÃUsQ“j9ªº®to{·Ü?×¹·³Z(µAÕ%póÞ-Áõ$ +vÒ´Õ%póÞ-raß-šµ‹A[]—|òbó¡¸Î‰×Ý\µº®ƒc>ˆd+—I>öîU2«ª+ÖrµÕ¥pmM0ÈÏû§½pUÝ+tnvêêR¸¶’ágÇhȕàö;¸ÚêR¸v#z§ÕõÆTlËoåÒÕ¥pÁá2¬ßÅerïFTþY´ê|[] +Wz¸Y˜s­Ú—_‹ò:d¦åj«KáÊÎN½7®´<žëÚ×Ô:ÛV—•ŸW­\&÷mý»ó¡ÖJËÕV·#ž¯¼mKVO ¸ç°çCHýb±­.…«ô^Øþ¸â–µZ«¥.‰Kฌîeç-Uë\-u\‰9×—nSý±Š¾.‰+nüM\¹^a\9w?ªJ§§ÒÊeôþê^Ì·E+—¾.‰K÷~V»\¥Î^\Úº$®ìäÓÛ¹Œ6²wÞè*Ò”˜Ô5*†ïí9ÊÏë óS|†ïYr¶¾ë…kx®î×-O“+þ‡åJ&ÉÕ½Á±™$—É‚ù…kx.£…夹æ“ä’ÿ°\á$¹º`³gÊL“+z†¯áïq¼pÀµ~†/îw|V“ä‚gʕ>ÃÑðwÍÆ*]/{]þÝX¥«Ë+Üï:H¥v¸œ ¤º¤.1ü]αJŒâŠ&pt…Øß½u-à]ö…üb×vÚ¢.=@þ®´k‡‡â‚©²Óß"ßܱ€#ÃqMî÷èÓÎaL´åœc†ÎisuÎ1¯;e0ò✝n 0îÀ9uŽ ø]s`Ýa ìÕ1–w« ôű•e֭ހòŽ9°´»³€zŽ9°¸Û¸e°Ž­ÀÖÝQ âHǘè9À §[Bè+àSBŸ#l p#ë”Ðg-œÂ8%ô€ÒWÕ)¡]äк$ôaZ€œŠ.EôQ·ûzâ’z‰‘n(°B?ŸŒ®J\b:‚˜bf C.‡1Æ(X¡÷¦"‡~™+›Ž ¢ +´Ð;!樈 +´Ð‡‘Ãy™ !ôŽ ì + +´Ð;"k”Z=]ޱú*q¥‰¤:…àp”^èÃIÈFPåB}0 Ù«\ˆ­²1¯q‰iG„SÀ?'"‰|ø€7\'„#CzY ´pA8bd¡ ¢›Ù*0«s!Ñόݮ€‚"ˆs÷§×ªÁO`‚¡ï‚a?ā}× +’pŒ=ÁÐïh€‚$#O°îG?Sp ç'>ñHÆ;ö[£' +4áw‚á# 9‡‘'X†_J)Vy‚N¤¢#‡ˆ„Sp(ˆÂ1â£ÒmœG]ƒQ΀ØpÌMŽ˜Ð9 ê蘛”­v NÌ•>§L ŽôˆJOڑjÓñ”^PºT%m·M’4 ¨Ss4CDØÒL˵v×iÛ/PÐ'ØÂQ3,ÇB@vé#bJ3$ ¯pF2Ä5íy݊G1DI ]¼ÄÇSâㆂ1ÁFˆqz@Á™`¡‹fXYiçÁ ¿XI© +Î|Õ,¨jk‚ œd™‘½¬ 6° ‹ÉsXC>°rHz€5EVFÔ +œåöÐ1‡ Ï àl sd Þ$Tê׌ ÌÇ3 ÔKÎcîç $ÆÇÜi:܀±¦;peu°ÃõfŽàB*ý@±ž1ð?j˜c† ÀŸ©Ã XÄ ë€í‡°”éL/AƒÈ)Qà¸ÖX°•Ã5CreŽ ˜Œ¸A8F†Xû©¥qB Õ* +3Cìuá,ùV…™!öªõا»@sá ±GéÈ l +SCô“‘5^)^`&°}Zâ'o†Z.ém‰¹‘tAalˆ=i¢0ò¡`–-†éêv¸ìË¢ù½ +\…´k‹×æ=²ÃµµE{Cl +w¸ +yåÎ`Ùä²4d—›Â5®BÞËàk[}±ÉÅO­>R]Ûë‰].ƒôjDêö˜\\2»T}pqÈ._ÛîC\ļxÙÃ{.úáږG\v¼y×Ë×÷Ƶµƒ¼X>öõÝ}rí‡ívy¡§ëÇ>¿·o®ÃÀín8,¯.vår¹¼~|ìý+á¡@òëôÕ½|õîûâ棐›ïÞ~wë·wBþôOÙ§ï¥x# +ÈEþó¿þß¾|ùçýò§¯¿‰ìó_þòõŸåŸ·íïÄÍÍ®ýÍÝGñææýÛÛ]û]»7yž½¹y»ÞU{s³Ù~ú›Û‡OþðËo珅/?ÿôë_ÙW¼{ÿöCés~þëo_þôßÿóuÛɏ߽ÙþßÇŸþò‘íþò—mG~ùüåïŸÚ5MäéÿiÁñ½endstream +endobj +75 0 obj +6308 +endobj +76 0 obj<>>>>>endobj +77 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +78 0 obj +31 +endobj +79 0 obj<>>>>>endobj +80 0 obj<>stream +xڝUKo1¾ó+F9%RÙfè-o!¥í6ª.Æ;œx=[Û ¢¿¾c/Bi«TpÁóú¾o|o¥pʟÎ;Ðíƒ,[—“ÖûÛ!¤C˜léŸ÷`’§0–TáÉä¹±ž%ƒÆÞ>$G’Â(GãU¡¤ðŠLã܃4]»vúëd®8*üRX‡²¶Ê¯ÀbEÖCei¡rt …^9ö¦*rNÍôN€$#ÑYðs„+*K2ðøiô-ç’i7鄒™UŒÌ<Áxå<–0=>ºzÌÆGÓøŠÖ1ZH“Óä¿îpï³ þ¼@»P¸ü ÁWX`¿ú–"Ê"°ª6>Z¬ÐFJ!vÚ9ë+oE4º˜À%0ò0nå Ñ@Ž Ô‘Ãl7­`¼‘:³”×Ò;ð0”ä‘!8/L.l¾…àHסƒ…кa±@““ }É÷ê֎5L (ºå²æû5ÄÀ%ÚÔúV–üÐÖÊ pI´…è’u֍Š1§nR‚ŸA¿“Ùx’¤¹™£›Ém{”eÜNѸÏD›€ŸK‰§àéÁ3Í"ø^cÍE›µGç>àŠe¸×C§Ç÷Ùõ;x¸½JÓóáôäŒyØþO—šä »?^k¨pQUc~Ä8Ó*Wæ6íh¯¤««0 Ü´¥òs^îÿ(j#C#„æy?¨Ès,˒ìKÐ1Í,-] PdäüXZUù-'tñAEbGYv͋ÐfÉpg(ÚìÆÊ …®«sU¥×[ï 696Ã{1³ç®K]7 kç©T?¸öb½Š¼íwŸán¾…>=楷|^ô + TüîÕKN»Ó“=¼A¾%ª m*ïÚÃ(ã!$¿Ï0 YvbÃ̐iïȶ–Õýý>>>>>endobj +83 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041T072PIÑp rt QÐUp VÎO+)O,JUNM.-Ê,©TJ-È/*Ñ ÉâÒi҅ê2‰˜˜˜é™)€ù† +ÁÉù© Q×®@.ü7 £endstream +endobj +84 0 obj +118 +endobj +85 0 obj<>>>>>endobj +86 0 obj<>stream +xÚ­•OÚ0Åï|Š9²Ò&K 7 +l…T´) {ââÆp•ØÔ6Úòíkc•V%]å@Æ¿7ö¼?ZtÌÀ „nòªõ)k=½ÄĐæMЃŒ¶CX`yŽê!ûîJžýÈyϑïÊüÆË$…‰ÈwrM4Ü-èAËþ+Ï6…(KñÎøÚ-¤— )µ.…o{ÐóU]3tàü#?<³Wa×Êm«àç‰ø¡Ó ^°õN:½9ád– IIø5ß4tÄßà³Éäžî•Æ +f\£,HŽ0AÅÖÜÞrɶ糹G"Í­„ÿ³…~'aD+ƙÒf/B*»—)ð¯·PÓ?¤õd~ H±–¤ª¬ w.n¡SÌw’é½±ïVH݀›%·¸ª¦I—˜ßRáÿŒímrûf¨ÖÛ¿Mîœ`ÏE§×)áUoPžb¬þ1Â\pï*Æ +l ™áÙt:…  üÞc° ç›Ý ¡×¶ŸU›JRèÕÃ]ç9K’§ÃÌG”2K$%¼nOèdxÆ^‚fì)ϵ=N!“„«» zbͪmyøÕ²ú¼c›qæ‚byh(Ŋ˜#ÌÕ] ÅËØ<âGøÂ8º1X¬ŒM̵ÈÅÑÛÑqÑÑ{aßúŸéE?6²æU×~žf­¯­_Ð&Ùûendstream +endobj +87 0 obj +522 +endobj +88 0 obj<>>>>>endobj +89 0 obj<>stream +xÚ-‹Í1…÷÷)ΒE™[Ͱ5˜5Óë¤n3TE¼½©È9›óó=ˆQb,êâp£FhÞ®À ‰`ÇXÚ +ržl»u+0Ø÷~ˆù}J +¯á•.ùƒNïCÊS¹’)ùS®4Îò¬Æ/Ûñ5iôY¦Ð¾­u"§endstream +endobj +90 0 obj +121 +endobj +91 0 obj<>>>>>endobj +92 0 obj<>stream +xÚuRÛjÜ0}÷WÌcïnöòؔ +¥´]úª•ÆY%²ÆÑÈMý÷‘³]Xƒå3ç6z®¸‘§Í–k°}u×V¾ì ÙAÛɟõf­{·„odM€Ö"3üòüÄWí£@WÐ43ôz¹«× +ž¡f†&…‚IùH¬o“Ášü;òP ¼ø|¡ŒŒI9hŒ¹†öèmöÁ2DÊj@d›e½PYã\REÏ< + a0J œaï£)ãԉ „D”a0Ì/”Ä@’Ó¤"còy:Ñ€¬/LşŽÞÿúûBœLB€'ÎØ×s;Räm½=÷3—Y7°?ÉÜ%4öˆo·¹÷Ñb‘uؙ1d𑳠aNce>«OÁ]˧3‡ ùðYüg Ÿ¤7JÓ{ð2Ë0³WD'¡Ïe³6¥ÓÉTÙRÌ3kwCò1C烈P8马¸üCW¿R,Ösಽ!‘ˆö§ÝKü3÷z˜ 7OÚ]ÙË¥oø©ÜA+¬ÜÐúÎ ‡zzaýÓý½zïüØæºÔ÷ën¶ç®W›õ<ñÖ=_moê r«ßŸÛêgõiã #endstream +endobj +93 0 obj +447 +endobj +94 0 obj<>>>>>endobj +95 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041T072PIÑp rt QÐUp VÎO+)O,JUNM.-Ê,©TJ-È/*Ñ ÉâÒi҅ê2‰[ëìò|ò“s““S‹‹‚2‹³‹AJ\C¸¹Ñ€%3endstream +endobj +96 0 obj +131 +endobj +97 0 obj<>>>>>endobj +98 0 obj<>stream +xÚ}WKo7¾ûWÌÑ$ْßí©nÀ@[¤¶‚öà Å¥$Æ\rCr½V~}¿!¹z¬í @‘¬È™ù3œ~?šÒþLézFçW$룻ùÑéç[šÞÒ|‰_®®/h^_Ѓª]Tô›”*zÐá9œÌ¿áìM§ùìøüvrŧËY‘Ïz>KÂ+Škø¿"’–ŠÔkcœŽª¢Nã×6’ ã¤0Ôå9‚k->ÚêÔyZzWã€ÏáÃ&DUO¸ +䞞Ofœ{¾Ö‚’Q;K•S¬C€ªò\‹¡Å'¯Œà¤Ñ‘U±sþ™8¼öªÆðõÖ븙d„`ãrr³Ã˜™Lée5JuKzTþEKУ?aæOý ^BÛ¨2ÞÆ… ZöȲ-\ƒä!à¸<Ð;3VâOk*N `K½Âõ$²ÑµŽ)³mëÀ Ô>t(â:- àEÀ­q4H·Æ9f#"sÒ¥œ ¹ñøí +© o­-CO%ªÆÌUiV„yPb3š ¹ +C؝¤q\ÆO–œŠoï¢ÀŠæ& %†:±aðE™”¬HY;m÷l¸'_p4éj¾Êt øA ]©t>7rß` Ö«u6ÆVg‡®3àŠB+×^’Œ¨'ÚY™£íˆ¤ôê;z:ÒD,”²èn©ô ¨/nëû ´ÌW$£qÙ̇ÁsI€‡Q·v€;Èןµ«·¢žQ?縳ç +<âhᝨ$§o€SEØÚ‚éê|úF¿ûH«tHSѺd½Ì¢¸J'ø»0µ_!â@Ö-Åx)»†ûÉ¿ê›&dã¤É…–yÚ¤œ=@¹Ò¬†èº.Pž}Î}#†guPÐI ©[CK¶¦è"zFWÔ6š%\(>ՋýV‹‹¢Å£²IŠFøÈóóþË*ž ¿Rh”ÔK §šÍVٝe¸Ù^/Z$E­J͹´]Óàp¯YŸ7zaC—*ô¯Ó^?n‡ŸtUjÍ}+c?ª|B‹ÈËÎß+˜€^€ñ1¾—©bWäÚ5ù€\ny.-ØïK<{YãÌð–ÏËŸéÞ©qL»‚¾¹Eș²GFý@äӎ«L¯zÈc6ê›èíÌJîã±ÍcYHmàj• ~gxe {e<3sù>+ïðñ_âõ!󸍍ÃGúxÇÀÓÉÇSœ¥‡0ûÌè¶'®>•Úµ¡€e-sa˜t@:`¥ø]ÙëÖb3©àûaò:p9·XAº·å¦Q§Øû®®!þéÌI)§_¿ ȳuMÏçé;5 Qr¥X”8—>6Àlú0,Ñ;ïUªbU +û›²ý·%áÍÎ4Æ^¹·5Ͱ+åíŠîàu¹VoKûݲ¿9‹Ç2´ Í@w"hI¢å¦Œhä4ýÒ¬eVÔªˆ Bî +<¦=¨ø7þ€ˆÆ™”Bz<Ð]½Æ²~lƒÄ Á =j~·RѸc}ýûþ¿ƒëô}°~íÕ× P^ ÷~ßm>H wƞJÌácöt\ž• +ø‡V+µ­ <ôÈ2õïͳJ-öÉ ¶ß»rQå™ +ýÊ.*ì VM?Oè_Üv©—vVNý‘ÏgcÜìŒ1»ÎÆøðG.nÎ&·8‰3×üïOó£ŽþúYU»endstream +endobj +99 0 obj +1404 +endobj +100 0 obj<>>>>>endobj +101 0 obj<>stream +xÚ]Q]o›0}çWœÇU4NXš=®Ëò6ikØ0æ܁Í|ífÙ¯ßuˆZ©Âºæ|ÝßBa%Âf›™ŠÇ¦¸?ÔP +M/_¶»ºÚ¡é>èn²Îr :ZïÐÈév¤½ÐãˆÁsäò:Ó ØŸ0è‚F ‰£€ų¿!N­LÐÆ3ŒÎ¢wÍs±B©6Õ:›Ck2Q`>t֝ÆKuC­·UQÍ@¢û7BŠn ‘4|¯¿~q¶ŽÓ<û±·'фNq ­Y¶¨ÌÈ70I}"´¾» ±x‚iÖ²ùû|ß÷ŸÊV¼:Qpz’U]‡Y3˖R‰+4ƒå%Æ|$ßÖI}ӒâJ Rž‹H.GôÁþ£îé­°.¢‡ñ“ˆN–o%÷¦Îצî»ÛïTµ‚Z©EfÿôåР\::ú>žµì~$“‚>>>>>endobj +104 0 obj<>stream +xڝT]o›0}çWÜÇíZÒ4…Ç %i¤ªc‚J}uÍ õâf;‹òïwZ©ÝŠ¥N „uçžã{ð¯$‡Kºr¸™ÁÕ¸J¾µÉꄼ„vG•ÅÍÚîË6Ò8Çìékûs\gÅI¯‹le9´h•1 Èó€ Þt¶!ÕXšPZ7j8x´ ™î¬Çì=Qú>0ˤD9MØ î„îÁX°ÈQü‹ŽyÊXÿÌ4Ýà…Š7ÆÔé‘‚ uЂ3/ŒvÀ©F O菈üÑÀ`Mo™r±v­`ÿåîžœá{ô1W$÷ìJ“|c÷S‘RžÒ«ò53Xrkô)eSm·)Š6„ÓÈÏtÇl•évä«é©ÎŠèTõñ]=ÔÍt«Š<ÕÃýöj+´[ۜœGá\5ÕE=Mºª›ï÷ˆ?7@ë"Ìë6»¡µL»6ã 72Âv[§›»i¾[­ß¡ˆgÁܽü”ã§Å+uô¼  ÿsJ̋ˬ¤ó +eX¯ÚäGòE8%endstream +endobj +105 0 obj +426 +endobj +106 0 obj<>>>>>endobj +107 0 obj<>stream +xڝ’MSÂ0†ïý{ÔC+ÅRˑv„¡C¤ñÄj¤$˜½IU“œö}v÷Ý}õBè˜Âml?ÝxCìÝd1„!à• ÅI$€—W÷ÈG£Ù5~1ztÖýnDÎÓÚG„®‰ZR\h¦`$…V²‚厔ì“ð]Á¿@˜Ó”˜Ê§ßà')ÎÚá‹LC*J.3ì0©×IE\„~mšµL¤¤–TV.b1ÿ‰H4—‚TPh"–ÆŒæª$‚¿7‚ƒ=CãvöÌL~²uLØÆ‰Ê'yÚÎÊw•æ¶äN&ä„W¾Ñg³-—¥ÎKCfÍ9+äšÉZTñ­>ÏÍê&àö±È‡íԂ©½!嬮m³ÃJÒµƒ…3ì8!¬øž›Ug¼b€õʰ/Ï(ùʋûÐKúAlóƋA†Á‡Ñ#* +} ŠAÁèNq}„ÛJ¥mºF!øwÝŽÍ +;6…IЃ&0º0 JŠã¦¶RнïõG%¿endstream +endobj +108 0 obj +383 +endobj +109 0 obj<>>>/Annots 53 0 R>>endobj +110 0 obj<>stream +xÚ՘ÍnÔ0Çïû>4þNŽ…R„„ì.°/,4ÈPߌ»jìܶRkâßÄ3žÿ8ýµÁ¨ÔI‚¨@M»y¹ß\ÝÖ×hDXЂ !¹¾î¿<Û>ß)ÔÑ«î<¨ópy¾ÿ¾y½ß”E©)æ‚ÍeûÆ  •žÖ"su÷whgøï¿¢«[Ž06Í´ÚyÃh?![DyQÅ|gÊ®é~*š(%x%\»Ó«ÿáÙHPa"M¸¾¶ˆ“‚à j¡ÖùDØH‰XÐVÏÄ&Ú¡ °[ÐÛ/zWœŽ§æ0œºóãQ粐kŠ{.¶vÅ>¶v0[QLô6¦$S W²1Ì@ÚÝ_Õ&Šaš¯DñøÒ¾œhïÿ¨þÏIý}<9 õ*’“É +¯+½(Ȋ¤²Â뺀N3Yñd\šªˆÐ`ÔM×ünõvŸç… d¬`1Ð?ÄLjˆÞQOœœ|.É(øî~‘àsIT“´à{<7áŠøÎ +”­:ª^u™‰c½.ýyäG3›_G`”{7X&÷\Øu“¬Ü{•Èƒ3;ΫOv‰”Msõæç¥IZHrvGòµ”hBÀ ¤u>¥8˜o5óÁ ƒ`Ý1QÒ"x+WÒ ì@ڙÃ~“؈!Aó„iÖÏ?Àëa84s;ˆ>™œçv +§¶Y¹œÙAêàÄ8s͋eNžl•4"ƒH µÚã ê!ìÀûO´Z¦µšHwp/õג,kâ”1õU<mÖIŒ³¥¼¹ë.—C?ɺÀëÿ^Ùþ˜ºïf¶,JÌ  %…rÂj¡¤£C_Î ¤½êÛ¹$×ր–Æ·,]#²+µƒ¤¼”Ä4)/ÌTˆéßìÕôÝù~.²Œ­ï¤mczu[ÁncX—$ŕ“·›íõí½@öëׇ¿‡^¡QD·êg×@Õx!‰]Ý ¢ùqóã×ï>>>>>endobj +113 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041T072PIÑp rt QÐUp VÎO+)O,JUNM.-Ê,©TJ-È/*Ñ ÉâÒi҅êÊÌ ¹†pr‡Âµendstream +endobj +114 0 obj +103 +endobj +115 0 obj<>endobj +116 0 obj<>endobj +117 0 obj<>endobj +118 0 obj<>endobj +119 0 obj<>endobj +120 0 obj<>endobj +121 0 obj<>endobj +122 0 obj<>endobj +123 0 obj<>endobj +124 0 obj<>endobj +125 0 obj<>endobj +126 0 obj<>endobj +127 0 obj<>endobj +128 0 obj<>endobj +129 0 obj<>endobj +130 0 obj<>endobj +131 0 obj<>endobj +132 0 obj<>/Outlines 115 0 R/PageMode/UseOutlines/OpenAction[79 0 R/XYZ null null null]>>endobj +xref +0 133 +0000000000 65535 f +0000000015 00000 n +0000000221 00000 n +0000000282 00000 n +0000000356 00000 n +0000000434 00000 n +0000000511 00000 n +0000000590 00000 n +0000000666 00000 n +0000000747 00000 n +0000000805 00000 n +0000000907 00000 n +0000001010 00000 n +0000001114 00000 n +0000001218 00000 n +0000001322 00000 n +0000001426 00000 n +0000001530 00000 n +0000001634 00000 n +0000001738 00000 n +0000001842 00000 n +0000001944 00000 n +0000002047 00000 n +0000002151 00000 n +0000002255 00000 n +0000002359 00000 n +0000002463 00000 n +0000002567 00000 n +0000002671 00000 n +0000002773 00000 n +0000002876 00000 n +0000002980 00000 n +0000003084 00000 n +0000003188 00000 n +0000003292 00000 n +0000003396 00000 n +0000003498 00000 n +0000003601 00000 n +0000003705 00000 n +0000003809 00000 n +0000003913 00000 n +0000004017 00000 n +0000004121 00000 n +0000004225 00000 n +0000004329 00000 n +0000004433 00000 n +0000004537 00000 n +0000004641 00000 n +0000004744 00000 n +0000004848 00000 n +0000004953 00000 n +0000005058 00000 n +0000005163 00000 n +0000005268 00000 n +0000005586 00000 n +0000005618 00000 n +0000005650 00000 n +0000005849 00000 n +0000005896 00000 n +0000005943 00000 n +0000005990 00000 n +0000006037 00000 n +0000006084 00000 n +0000006131 00000 n +0000006178 00000 n +0000006225 00000 n +0000006272 00000 n +0000006319 00000 n +0000006366 00000 n +0000006413 00000 n +0000006461 00000 n +0000006509 00000 n +0000006557 00000 n +0000006728 00000 n +0000006877 00000 n +0000013254 00000 n +0000013275 00000 n +0000013385 00000 n +0000013485 00000 n +0000013504 00000 n +0000013641 00000 n +0000014534 00000 n +0000014554 00000 n +0000014664 00000 n +0000014851 00000 n +0000014871 00000 n +0000015008 00000 n +0000015599 00000 n +0000015619 00000 n +0000015729 00000 n +0000015919 00000 n +0000015939 00000 n +0000016067 00000 n +0000016583 00000 n +0000016603 00000 n +0000016713 00000 n +0000016913 00000 n +0000016933 00000 n +0000017070 00000 n +0000018543 00000 n +0000018564 00000 n +0000018685 00000 n +0000019137 00000 n +0000019158 00000 n +0000019297 00000 n +0000019794 00000 n +0000019815 00000 n +0000019945 00000 n +0000020399 00000 n +0000020420 00000 n +0000020573 00000 n +0000021671 00000 n +0000021693 00000 n +0000021805 00000 n +0000021979 00000 n +0000022000 00000 n +0000022055 00000 n +0000022160 00000 n +0000022303 00000 n +0000022408 00000 n +0000022527 00000 n +0000022635 00000 n +0000022783 00000 n +0000022892 00000 n +0000022998 00000 n +0000023154 00000 n +0000023249 00000 n +0000023406 00000 n +0000023522 00000 n +0000023630 00000 n +0000023764 00000 n +0000023861 00000 n +0000023961 00000 n +trailer +<> +startxref +24144 +%%EOF diff --git a/doc/ssr.shtml b/doc/ssr.shtml new file mode 100644 index 0000000000..91ece988ed --- /dev/null +++ b/doc/ssr.shtml @@ -0,0 +1,252 @@ + + + + + + DRAFT - CUPS Software Security Report + + + +

Scope

+ +

Identification

+ +This software security report provides an analysis of possible security +concerns for the Common UNIX Printing System ("CUPS") Version 1.0.

+ +

System Overview

+ +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +

This software security report is organized into the following sections:

+ +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Local Access Risks
  • +
  • 4 - Remote Access Risks
  • +
  • A - Glossary
  • +
+ +

References

+ +

CUPS Documentation

+ +The following CUPS documentation is referenced by this document: + +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan +
  • CUPS-IDD-1.0: CUPS System Interface Design Description +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual +
  • CUPS-SDD-1.0: CUPS Software Design Description +
  • CUPS-SPM-1.0: CUPS Software Programming Manual +
  • CUPS-SSR-1.0: CUPS Software Security Report +
  • CUPS-STP-1.0: CUPS Software Test Plan +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual +
  • CUPS-SVD-1.0.x: CUPS Software Version Description +
+ +

Other Documents

+ +The following non-CUPS documents are referenced by this document: + +
    +
  • IEEE 1387.4, System Administration: Printing (draft) +
  • IPP/1.0: Additional Optional Operations - Set 1 +
  • IPP/1.0: Encoding and Transport +
  • IPP/1.0: Implementers Guide +
  • IPP/1.0: Model and Semantics +
  • RFC 1179, Line Printer Daemon Protocol +
+ +

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. + +

Security Breaches

+ +

Since the default installation creates a world-readable request directory, +it is possible for local users to read the contents of print files before they +are printed. + +

This problem can be alleviated by making the request directory readable only +by the user specified in the CUPS configuration file. + +

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. + +

Denial of Service Attacks

+ +

Like all internet services, the CUPS server is vulnerable to denial of +service attacks, including: + +

    + +
  1. 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 determined + attack. + +

  2. 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. + +

  3. 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. + +

  4. 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. + +

  5. 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. + +

+ +

Security Breaches

+ +

The current CUPS server only supports Basic authentication with +usernames and passwords. This 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. + +

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. + +

The next minor release of CUPS will support Digest authentication of +the entire message body using separate MD5-based username and password +files. This will protect password information and prevent unauthorized +access due to compromised account passwords. + +

Glossary

+ +

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. + +
+ +

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 Printer 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 + +
PCL +
Page Control Language + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
+ + + diff --git a/doc/stp.html b/doc/stp.html new file mode 100644 index 0000000000..ec2a16f929 --- /dev/null +++ b/doc/stp.html @@ -0,0 +1,145 @@ + + +DRAFT - CUPS Software Test Plan + + + + + +

+

DRAFT - CUPS Software Test Plan


+CUPS-STP-1.0
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Local Tests +
+
4 Remote Tests +
+
A Glossary + +
+

1 Scope

+

1.1 Identification

+ This software test plan provides detailed tests that are used to +evaluate the stability of the Common UNIX Printing System ("CUPS") +Version 1.0. +

1.2 System Overview

+ The Common UNIX Printing System provides a portable printing layer for + UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

1.3 Document Overview

+ This software test plan is organized into the following sections: +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Local Tests
  • +
  • 4 - Remote Tests
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+ The following CUPS documentation is referenced by this document: +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.0: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.0: CUPS Software Design Description
  • +
  • CUPS-SPM-1.0: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.0: CUPS Software Security Report
  • +
  • CUPS-STP-1.0: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.0.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+ The following non-CUPS documents are referenced by this document: +
    +
  • IEEE 1387.4, System Administration: Printing (draft)
  • +
  • IPP/1.0: Additional Optional Operations - Set 1
  • +
  • IPP/1.0: Encoding and Transport
  • +
  • IPP/1.0: Implementers Guide
  • +
  • IPP/1.0: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
+

3 Local Tests

+

4 Remote Tests

+

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.
+
+

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 Printer 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
+
PCL
+
Page Control Language
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/stp.pdf b/doc/stp.pdf new file mode 100644 index 0000000000..7d51055f8a Binary files /dev/null and b/doc/stp.pdf differ diff --git a/doc/stp.shtml b/doc/stp.shtml new file mode 100644 index 0000000000..511764e3d5 --- /dev/null +++ b/doc/stp.shtml @@ -0,0 +1,169 @@ + + + + + + + DRAFT - CUPS Software Test Plan + + + +

Scope

+ +

Identification

+ +This software test plan provides detailed tests that are used to evaluate +the stability of the Common UNIX Printing System ("CUPS") Version 1.0. + +

System Overview

+ +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +This software test plan is organized into the following sections: + +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Local Tests
  • +
  • 4 - Remote Tests
  • +
  • A - Glossary
  • +
+ +

References

+ +

CUPS Documentation

+ +The following CUPS documentation is referenced by this document: + +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan +
  • CUPS-IDD-1.0: CUPS System Interface Design Description +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual +
  • CUPS-SDD-1.0: CUPS Software Design Description +
  • CUPS-SPM-1.0: CUPS Software Programming Manual +
  • CUPS-SSR-1.0: CUPS Software Security Report +
  • CUPS-STP-1.0: CUPS Software Test Plan +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual +
  • CUPS-SVD-1.0.x: CUPS Software Version Description +
+ +

Other Documents

+ +The following non-CUPS documents are referenced by this document: + +
    +
  • IEEE 1387.4, System Administration: Printing (draft) +
  • IPP/1.0: Additional Optional Operations - Set 1 +
  • IPP/1.0: Encoding and Transport +
  • IPP/1.0: Implementers Guide +
  • IPP/1.0: Model and Semantics +
  • RFC 1179, Line Printer Daemon Protocol +
+ +

Local Tests

+ + + + +

Remote Tests

+ + + + +

Glossary

+ +

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. + +
+ +

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 Printer 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 + +
PCL +
Page Control Language + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
+ + + diff --git a/doc/sum.html b/doc/sum.html new file mode 100644 index 0000000000..21f2d24814 --- /dev/null +++ b/doc/sum.html @@ -0,0 +1,511 @@ + + +DRAFT - CUPS Software Users Manual + + + + + +

+

DRAFT - CUPS Software Users Manual


+CUPS-SUM-1.0.0b1
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
Preface + +1 - Printing System Overview + +2 - Using the Printing System + +3 - Standard Printer Options + +
+

Preface

+ This software users manual describes how to use the Common UNIX +Printing System ("CUPS") Version 1.0.0. +

System Overview

+ The Common UNIX Printing System provides a portable printing layer for + UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

Document Overview

+

This software users manual is organized into the following sections:

+
    +
  • 1 - Printing System Overview
  • +
  • 2 - Using the Printing System
  • +
  • 3 - Standard Printer Options
  • +
  • 4 - Checking the Status Via the Web
  • +
+

1 - Printing System Overview

+

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 MacOS, UNIX has no standard interface or system +in place for supporting printers. Among the solutions previously +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 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.

+

The Common UNIX Printing System, or 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, or IPP. IPP has been embraced by dozens of printer +and printer server manufacturers, and will be supported by the next +Microsoft Windows operating system.

+

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 secure printing solution than +older ones.

+

IPP is layered on top of the Hyper-Text Transport Protocol, or HTTP, +which is the basis of web servers on the Internet. This allows the user +to view documentation and status information on a printer or server +using their web browser.

+

CUPS provides a complete IPP/1.0-based printing system that provides +Basic authentication and domain or IP-based access control. Digest +authentication and TLS encryption will be available in future versions +of CUPS.

+

Jobs

+

Each file 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.

+

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. Backend filters perform the most +important task of all - they send the filtered print data to the +printer.

+

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 Processors, or RIPs, that convert +PostScript or image files into bitmaps that can be sent to a raster +printer.

+

CUPS provides backends for printing over parallel and serial ports, +and over the network via the JetDirect (AppSocket), Server Message +Block, and Line Printer Daemon protocols.

+

Printer Drivers

+

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes a sample printer driver for Hewlett-Packard +LaserJet and DeskJet printers. While this driver does not generate +optimal output for different printer models, it does 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. If there is only one occurrence of a +printer on a network, then that printer can be accessed using its name +alone. If more than one printer exists with the same name, users must +select the printer by specifying which server to use (e.g. +"printer@host1" or "printer@host2".)

+

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 goes down!

+

2 - Using the Printing System

+

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) and Berkeley ( +lpr) printing commands. To print a file to the default printer +on the system (or your only printer if you have only one) you just need +to type:

+
    +
    +% lp filename ENTER
    +
    +
+

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!

+

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 or +serial port, or available over the network.

+

To see a list of available printers, use the lpstat + command:

+
    +
    +% 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.

+

To print to a specific printer, use the "-d" option to the lp + command:

+
    +
    +% lp -d printer filename ENTER
    +
    +
+

or the "-P" option to 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 command allows you to pass printer options using +the "-o" option:

+
    +
    +% lp -o landscape -o scaling=75 -o media=A4 filename.jpg
    +
    +
+

The lpr command has no command-line option for printer +options.

+

The available printer options vary depending on the printer. The +standard options are described in Chapter 3.

+

Printing Multiple Copies

+

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. To get collated +copies use the lp command with the "-o Collate=True" +option:

+
    +
    +% lp -n num-copies -o Collate=True filename ENTER
    +
    +
+

Checking the Printer Status from the Command-Line

+

The lpstat command can be used to check for jobs that +you have submitted for printing:

+
    +
    +% lpstat ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +
    +
+

The jobs are listed in the order they will be printed. To see which +files and printers are active, use the "-p" option:

+
    +
    +% lpstat -p ENTER
    +printer DeskJet now printing DeskJet-1.
    +
    +
+

Or to show the jobs and the printers, use the "-o" and "-p" options:

+
    +
    +% lpstat -o -p ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +printer DeskJet now printing DeskJet-1.
    +
    +
+

Checking the Printer Status from the Web

+

Since CUPS uses the Internet Printing Protocol, it is also a +full-featured 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!

+

Canceling a Print Job

+

The cancel command cancels a print job:

+
    +
    +% cancel job-id ENTER
    +
    +
+

The job-id is a 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 command.

+

General Options

+

The following options apply when printing all types of files.

+

Selecting the Media Size, Type, and Source

+

The "-o media=xyz" option sets the media size, type, and/or source:

+
    +
    +% lp -o media=Letter filename ENTER
    +% lp -o media=Letter,MultiPurpose filename ENTER
    +% lp -o media=Letter,Transparency filename ENTER
    +% lp -o media=Letter,MultiPurpose,Transparency filename ENTER
    +
    +
+

The available media sizes, types, and sources depend on the printer, +but most support the following options (case is 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.

+

Setting the Orientation

+

The "-o landscape" option will rotate the page 90 degrees to print +in landscape orientation:

+
    +
    +% lp -o landscape filename ENTER
    +
    +
+

Printing On Both Sides of the Paper

+

The "-o sides=two-sided-short" and "-o sides=two-sided-long" options +will enable duplexing on the printer (if the printer supports it.) The +"two-sided-short" option is suitable for landscape pages, while the +"two-sided-long" option is suitable for portrait pages:

+
    +
    +% lp -o sides=two-sided-short filename ENTER
    +% lp -o sides=two-sided-long filename ENTER
    +
    +
+

Selecting a Range of Pages

+

The "-o page-ranges=pages" option selects a range of pages for +printing:

+
    +
    +% lp -o page-ranges=1 filename ENTER
    +% lp -o page-ranges=1-4 filename ENTER
    +% lp -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-range" option.

+

To select the even or odd pages, use the "-o page-set=set" option:

+
    +
    +% lp -o page-set=odd filename ENTER
    +% lp -o page-set=even filename ENTER
    +
    +
+

Setting the Brightness

+

You can control the overall brightness of the printed output using +the "-o brightness=percent" option:

+
    +
    +% lp -o brightness=120 filename ENTER
    +
    +
+

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:

+
    +
    +% lp -o gamma=1700 filename ENTER
    +
    +
+

Values greater than 1000 will lighten the print, while values less +than 1000 will darken it.

+

Text Options

+

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:

+
    +
    +% lp -o cpi=12 filename ENTER
    +
    +
+

Setting the Number of Lines Per Inch

+

The "-o lpi=value" option sets the number of lines per inch:

+
    +
    +% lp -o lpi=8 filename ENTER
    +
    +
+

Setting the Number of Columns

+

The "-o columns=value" option sets the number of text columns:

+
    +
    +% lp -o columns=2 filename ENTER
    +
    +
+

Setting the Page Margins

+

Normally the page margins are set to the hard limits of the printer. +To adjust the page margins use the "-o page-left=value", "-o +page-right=value", "-o page-top=value", and "-o page-bottom=value" +options:

+
    +
    +% lp -o page-left=value filename ENTER
    +% lp -o page-right=value filename ENTER
    +% lp -o page-top=value filename ENTER
    +% lp -o page-bottom=value filename ENTER
    +
    +
+

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:

+
    +
    +% lp -o prettyprint filename ENTER
    +
    +
+

Image Options

+

The following options apply when printing image files.

+

Scaling the Image

+

The "-o scaling=percent" and "-o ppi=value" options change the size +of a printed image:

+
    +
    +% lp -o scaling=percent filename ENTER
    +% lp -o ppi=value filename ENTER
    +
    +
+

The scaling percent 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.

+

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:

+
    +
    +% lp -o hue=value filename ENTER
    +
    +
+

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: +

+ + + + + + + + +
Originalhue=-45hue=45
RedPurpleYellow-orange
GreenYellow-greenBlue-green
YellowOrangeGreen-yellow
BlueSky-bluePurple
MagentaIndigoCrimson
CyanBlue-greenLight-navy-blue
+
+

+

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:

+
    +
    +% lp -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.

+ + diff --git a/doc/sum.pdf b/doc/sum.pdf new file mode 100644 index 0000000000..c2d34fef56 --- /dev/null +++ b/doc/sum.pdf @@ -0,0 +1,949 @@ +%PDF-1.2 +%âãÏÓ +1 0 obj<>endobj +2 0 obj<>endobj +3 0 obj<>endobj +4 0 obj<>endobj +5 0 obj<>endobj +6 0 obj<>endobj +7 0 obj<>endobj +8 0 obj<>endobj +9 0 obj<>endobj +10 0 obj<>endobj +11 0 obj<>endobj +12 0 obj[10 0 R +11 0 R +]endobj +13 0 obj<>endobj +14 0 obj<>endobj +15 0 obj[14 0 R +]endobj +16 0 obj<>endobj +17 0 obj<>endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj<>endobj +22 0 obj<>endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj<>endobj +26 0 obj<>endobj +27 0 obj<>endobj +28 0 obj<>endobj +29 0 obj<>endobj +30 0 obj<>endobj +31 0 obj<>endobj +32 0 obj<>endobj +33 0 obj<>endobj +34 0 obj<>endobj +35 0 obj<>endobj +36 0 obj<>endobj +37 0 obj<>endobj +38 0 obj<>endobj +39 0 obj<>endobj +40 0 obj<>endobj +41 0 obj<>endobj +42 0 obj<>endobj +43 0 obj<>endobj +44 0 obj<>endobj +45 0 obj<>endobj +46 0 obj<>endobj +47 0 obj<>endobj +48 0 obj<>endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj<>endobj +52 0 obj<>endobj +53 0 obj<>endobj +54 0 obj<>endobj +55 0 obj<>endobj +56 0 obj<>endobj +57 0 obj<>endobj +58 0 obj<>endobj +59 0 obj<>endobj +60 0 obj<>endobj +61 0 obj<>endobj +62 0 obj<>endobj +63 0 obj<>endobj +64 0 obj<>endobj +65 0 obj<>endobj +66 0 obj<>endobj +67 0 obj<>endobj +68 0 obj<>endobj +69 0 obj<>endobj +70 0 obj<>endobj +71 0 obj<>endobj +72 0 obj<>endobj +73 0 obj<>endobj +74 0 obj<>endobj +75 0 obj<>endobj +76 0 obj<>endobj +77 0 obj<>endobj +78 0 obj<>endobj +79 0 obj<>endobj +80 0 obj<>endobj +81 0 obj<>endobj +82 0 obj<>endobj +83 0 obj<>endobj +84 0 obj<>endobj +85 0 obj<>endobj +86 0 obj<>endobj +87 0 obj<>endobj +88 0 obj<>endobj +89 0 obj<>endobj +90 0 obj<>endobj +91 0 obj<>endobj +92 0 obj<>endobj +93 0 obj<>endobj +94 0 obj<>endobj +95 0 obj<>endobj +96 0 obj<>endobj +97 0 obj<>endobj +98 0 obj<>endobj +99 0 obj<>endobj +100 0 obj<>endobj +101 0 obj<>endobj +102 0 obj<>endobj +103 0 obj<>endobj +104 0 obj<>endobj +105 0 obj<>endobj +106 0 obj<>endobj +107 0 obj<>endobj +108 0 obj<>endobj +109 0 obj<>endobj +110 0 obj<>endobj +111 0 obj<>endobj +112 0 obj<>endobj +113 0 obj<>endobj +114 0 obj<>endobj +115 0 obj<>endobj +116 0 obj<>endobj +117 0 obj<>endobj +118 0 obj<>endobj +119 0 obj<>endobj +120 0 obj<>endobj +121 0 obj<>endobj +122 0 obj<>endobj +123 0 obj<>endobj +124 0 obj<>endobj +125 0 obj<>endobj +126 0 obj<>endobj +127 0 obj<>endobj +128 0 obj<>endobj +129 0 obj<>endobj +130 0 obj<>endobj +131 0 obj<>endobj +132 0 obj<>endobj +133 0 obj<>endobj +134 0 obj<>endobj +135 0 obj<>endobj +136 0 obj<>endobj +137 0 obj<>endobj +138 0 obj<>endobj +139 0 obj<>endobj +140 0 obj<>endobj +141 0 obj<>endobj +142 0 obj<>endobj +143 0 obj<>endobj +144 0 obj<>endobj +145 0 obj<>endobj +146 0 obj<>endobj +147 0 obj<>endobj +148 0 obj<>endobj +149 0 obj<>endobj +150 0 obj<>endobj +151 0 obj<>endobj +152 0 obj<>endobj +153 0 obj<>endobj +154 0 obj<>endobj +155 0 obj<>endobj +156 0 obj[16 0 R +17 0 R +18 0 R +19 0 R +20 0 R +21 0 R +22 0 R +23 0 R +24 0 R +25 0 R +26 0 R +27 0 R +28 0 R +29 0 R +30 0 R +31 0 R +32 0 R +33 0 R +34 0 R +35 0 R +36 0 R +37 0 R +38 0 R +39 0 R +40 0 R +41 0 R +42 0 R +43 0 R +44 0 R +45 0 R +46 0 R +47 0 R +48 0 R +49 0 R +50 0 R +51 0 R +52 0 R +53 0 R +54 0 R +55 0 R +56 0 R +57 0 R +58 0 R +59 0 R +60 0 R +61 0 R +62 0 R +63 0 R +64 0 R +65 0 R +66 0 R +67 0 R +68 0 R +69 0 R +70 0 R +71 0 R +72 0 R +73 0 R +74 0 R +75 0 R +76 0 R +77 0 R +78 0 R +79 0 R +80 0 R +81 0 R +82 0 R +83 0 R +84 0 R +85 0 R +86 0 R +87 0 R +88 0 R +89 0 R +90 0 R +91 0 R +92 0 R +93 0 R +94 0 R +95 0 R +96 0 R +97 0 R +98 0 R +99 0 R +100 0 R +101 0 R +102 0 R +103 0 R +104 0 R +105 0 R +106 0 R +107 0 R +108 0 R +109 0 R +110 0 R +111 0 R +112 0 R +113 0 R +114 0 R +115 0 R +116 0 R +117 0 R +118 0 R +119 0 R +120 0 R +121 0 R +122 0 R +123 0 R +124 0 R +125 0 R +126 0 R +127 0 R +128 0 R +129 0 R +130 0 R +131 0 R +132 0 R +133 0 R +134 0 R +135 0 R +136 0 R +137 0 R +138 0 R +139 0 R +140 0 R +141 0 R +142 0 R +143 0 R +144 0 R +145 0 R +146 0 R +147 0 R +148 0 R +149 0 R +150 0 R +151 0 R +152 0 R +153 0 R +154 0 R +155 0 R +]endobj +157 0 obj<>endobj +158 0 obj<>endobj +159 0 obj<>endobj +160 0 obj<>endobj +161 0 obj<>endobj +162 0 obj<>endobj +163 0 obj<>endobj +164 0 obj<>endobj +165 0 obj<>endobj +166 0 obj<>endobj +167 0 obj<>endobj +168 0 obj<>endobj +169 0 obj<>endobj +170 0 obj<>endobj +171 0 obj<>endobj +172 0 obj<>endobj +173 0 obj<>endobj +174 0 obj<>endobj +175 0 obj<>endobj +176 0 obj<>endobj +177 0 obj<>endobj +178 0 obj<>endobj +179 0 obj<>endobj +180 0 obj<>endobj +181 0 obj<>endobj +182 0 obj<>endobj +183 0 obj<>endobj +184 0 obj<>endobj +185 0 obj<>endobj +186 0 obj<>endobj +187 0 obj<>endobj +188 0 obj<>endobj +189 0 obj<>endobj +190 0 obj<>endobj +191 0 obj<>endobj +192 0 obj<>endobj +193 0 obj<>endobj +194 0 obj<>endobj +195 0 obj<>endobj +196 0 obj<>endobj +197 0 obj<>endobj +198 0 obj<>>>>>endobj +199 0 obj<>stream +xÚíßoä8rÇ¥nõË<ÉÞíwº= $@Æ#{ܳ;@hlk“}8 $QÈC‡ÍíÞ%Áæön$¸ÿ>ýËÝúAJUEJ¢|懛tó#¿U$‹ê¿¼¹Ñö·â«;ñá£øýÿ¼yoùæ/âCôõÍWû_~øøñ&_º¹ww·7÷ûZß¾Ìÿíý·ï³~›Œöåþ|ܗOûò¸/ßìË?ýûûoů?ÿöÃû÷nßÿ‹ØÜÞ¾€Gq/¾}zS¼Ì¯\fE>Ý­V««‹]ÙþÇêþiê\òquzªrqyý4M.yw¥F*Á­î'Æ%ﺘžËåu2.<Ôí~ +\W¹ø«Äq®‡Ðã•ˍÃ\w\*›æΌ•Ý1³Ìõ(<óòEâW~åY)þµS\wžµ2Û8Ã%…g³\;Âe¬v‡Ì—¼ò¬ÿíè\yèõQ¾™ëÁë©Ì’1¹n½ÞŠ¿Ë²Z·±¶åí(\2ô<ÁÀI!¬–/ç‹Àâ€Á°`à´dðŦåy끸z÷[fšÍ50Ö,‚+ò/³¸>{#”yï\™7Jù²g®<‡‹ Šà¾Â³´¦ … 퀉huŠÑ¹roÔ²é‹+— 9Å`™ãÅ`ž‹,öD.9>–ç÷À%àòë\™çDÙX撡\3Ë\‘çHYZåʏ+íGÛ-ٚÅeƒ'oZ‘z°¿«a’öÎI6Ø0¸Ä`S‹Ÿyйò°È`>‹,ò¾+’ÂX9Ú¹FÂ"‚Í©\éFÈ1ńÈ%ÆÂ"‚-i\¹É \Ø[x}YX-™‘!‚µHÞ2éöՒ•ZgŒJdðá`I5üÄ>¡ žKši¦%碞 F\‡ò™mˆ`e…2+z*‚kˆ`Cf{™\´É°ÄrÅc9dž(ϰ\3œ=Á3D07Ãþ¬¢‰kWä„zà¸ÐBštø(®ldÌP° † ¯†AÑ{ÁIØÃº!­Ÿ!¸2~`6ހ%Ý\±+¢A°u7WèˆÆ“útren rÀf\±cÅôaIWèØp!Ÿô²ƒ+wÆ%Óºtp¥Î .Jœup ÇfZʒV.éàpáæüº•+sp¸pÛHA+RåýA±PV4kå +Š ‰ÊÑÆ…Uù±PÓcÓ…Tù`h®‚dCÀUùÍà\Cœ·p9°·Æ6ęž+sQäт–h¹ÀE‘G; µ–K8ª8SZ踤«ª›úsWF «žìü¯š±?ÿŽÏ4­¨r†õó¾cÀ +¢–(®¥–KVnܖÐJt­‰†KÐbV®¹–ëø1eÃ8‰Ÿ À™^ŽËÓsAI½r|¸)ЖœéµFr­µ\yéùÖ 1³$PsÑyµsZ®ƒíÍ΃0³¤ô35— :¯v®™žë¬’²êA?s`‡k,׳q)¸ÎڞáÍ£ô‰Š+§ÆP\K-×YcÊ^IŠ}è@_{x®¹ž+~~D!eñcÈkíJ(ßÁåé¹²ãßÊ)fˆ˜(Š+$ša'×ZËuø¬ÅáGø-»Na›+¸$Õ ;¹=WtÍ3T£í6_Á•QͰ“Ë×s>쉸<Ȑ‚d¯œ`¹æ§ÚJ®ƒq\PwŽ‘"P½ò¬Àr-ÂgyRr•DвJ8{ªl,ñ\ñócPs¥¬Ujgˆ¸hpåd3lçÊ*8 .ÉÚ,IqºD٘x.ùlj®“I‘6Kr\¸V\ûŽz®”µg‡z ÊÆšÂǏÑpI֞]g/\ŒôÅv®ü( +®c‰{v1ª‹@“YAá*ŽJ¯ã΁SŠ2) ÉƂÆuTzW̯ 剀&k×Qéu\!g~IÔ³î Šë¨ô®Œw†b$HÑÆŒÈuTz WÌÛìïzþó*—dL¯N®ƒÒk¸BÞáLŒyø@’5•ë ôj®œyŠ‘b3ö6 +*×AéÕ\ 7³HªÊ3¦W7×^éÕ\‚™¹#1Ž(QT@çÚ[w¬_W®†Ø%p› +ëP¹[)¸ö½*®ƒÝKFÈ!ÝJ•¨]R6¿ÊuîDK4YÐ 1BÀÊ"¨r­Ë¦Î®ç"œ¦`·ae.ĞÍ\c˲¢Îj\¹†+=òätCL29\jLbÞüG}ÿ³É=?ôi%ÚÓV¸G6*Gòä‹J\±’Kžz‘ Q"ì +Ñ¡Ö$‚ÀºÎ•)¹ÒSå”û"tðÑáLïûw¯´¹-kfÃOÕ¹¢“ÆHz¾UˆçÊ9^ùüþE^WT¹JQc_Ñ >:\b|ɢɕ*¸Ê©(1Ù£î x9Ü`´)irå +®²ÞdäEà¹"–l4lb^4¹Ž¶Zá +Ë–¼“Oí¥Ä%X²QŸ˜§Û{Šuq™«šõÑôT±Zù¬òpŠ}Œ2W\1촇Ô?@Ë¡vñw~¯ÉÛBÉ%\aÅòòR5õêí$ß¿øÔ¿à +)•+eÊás9LV÷¸º£y¿˜T¬ÌÏ&É%xQ”ó\!/ŠrKšÈ¡Ã\¹¡ºÊ•q£Cǹҗ&‡G®˜ºÍñ£C§¹ÄK“ù#WøÒäðÈÅٚŸ—|q2àÊ^œÌc¹&!óåE àܲûѼ<|[Éå¦Ä³e¾\çr£ú©wq]Ùö;ïö6®ó)£í®FšMÀ¹å5‚ë¼oSŸœ‰’kÉáZª¹Ê3éË—`»/5¾Fuj]œs¸æJ®\}¾²Ý—@cƵ.z.OÉ%ÔçüMµ½êrSk]\s¸Ö +®´©r€rË3,×\¾¬U\‡+Pp…ÍÇh™ë`°ºÜ¹Zg®Y“ëY4ü‹ðd÷€rËšk­æòU\õë|(®ÆÀ“œïüÉcx4×¢•kÿ_Â«ô`Qu,‰Šk©tEÕxѨìdžÛn,»¹Ž/Ÿ7N>{•ëå.Î9\FYÅ?P›ØkW)-¥:Äçܞz=W£QõÐé˜Ç¨0jƒá:§)²äÊ.®9\õF¢˜ïi(—gÛ¹¤†+Ös®z£ÚLٛå PaTá:ÿC‘ý¯æò9\µFõ‹§Ïå÷Á¥¸Î×Í¥h”Õìj[®Î̹šº¡¸Î×Í¥»¨Ö˞.©áŠÔ:¯¸Î‡àj6Š•0aTP˜èaxʹ­v±yÁÕl$”Žŵ@qejÿ•iâ(Åu>W³‘–+³Ä+ãÇsRëbó:‚«Ù(T:"×Ã%½†"·®S×ù0\FZ®”F•úpüŠÆ5z]©¸Î‡áj4*W?"ŠkS®¿–Ê.6®óa¸´\À£ +õÀhvU]<Š6«ÞȀ«@sªŸú‰¦‹õë|(®z#-Wl‘k£ÅDÝÅúu>W½‘–+⇇…Úà4Ûû.Ö¯ó¡¸êÂZšê‰KXãò W)T­t±vÇUkÄçš!¹üué§G¿|ÜöXª»X»Î‡ãª5%Å®p…v¸Jù‡åxã°í¨»X»Î‡ãª5jÄQ)–+(pë”BÅUz?”¢‹{ѦrUEõˆ(>ryýrem\Õë|H.ÅÀr#,׈+×Åó§ R¹ªÒúT \²g.©¹Å¡¸Î‡äª6Êj’-=,×҈«håW¥‘¬…æ©\9‡«Ú(¬N0qäêÎ=\÷ÈU¹Î‡åª6ŠÉø[®l\®˜ÃUi”žO•Ï›¼£se®J#YîevŠ7L–•¸$‡«ÚHœÏ¿<WÒ'Wù:š«Ú(mœWºÀ•r¸ªj‘ Øs™,—Q\a;WÎáª6ª®ŒƒÈ ®Òu>è{¥”ºãr=ìßaæ_cºK©;2×UýúZõeC¥7Ì)êªOÔ'Užâ¢”¶wÆ\¢‘¾QÍÓ/O5ë2¸6ÕÍО¸>7W4՗yåçÎϘU\ëêí‡K*N”ª/4LO[üuó¨“k9¨–Ö¢<Áj鵺 ®EQ™šýp…ª£2(σ°’&S¯Ëà +ª–Ò Wþ|ðtQ®[~uíù´^Y—Á5«|t?\éé Pޖ>´$çì +e]>WÖ'W\:±ŽÎÞ¥ä²ÎÉ皺ªm~õ§VwÒ>¹DI äyV5°ôBfM]—:>ÝNâYo\ayNԔþlÔZk¹ÚêvÄó•·mÉê© ײóö|©_,¶Õ¥p•Þ ÛWܲV«sµÔ%q —ѽ켥j«¥.ƒ+1çZàÒmê¡#VÑ×%qōŸôÀ•ë¦Á•s÷£ªpz*­\FïߨîÅ|Y´ré뒸tïgµËUêìuÑÁ¥­KâÊN>½Ëh#{獮BíA‰I]£bøÞžc¡|½Þ0_Ågøž%g‹á{±^¹†çê~Ýò4¹â¿Y®d’\Ý›Ir™,˜_¹†ç2ZXNšk1I.ù7ËL’«{6¡\³ir…/0ð5ü>ŽW®¸¢øâ¾Çg=I.x¡\é  ¿×l¬Òõ²×¥á÷ЍUºº¼Æ}o sTj‡Ë¹@ªKêÃïå«Ä(®prGW(ýÞ[×Ñe_Èï)vm§-ìÒä÷J»px(.˜ZÀ!;ý-òûÍ 82×侏>íÀD[Î9fèœ6€1WçsÔ)s€‘ç˜ètK€qÎ9°°sÅïšëûe¯Ž9°¼[ ¥/Ž­,³nõ”?ṕ¥ÝÔṕÅÝÆ(ƒuluG}€Š#s`¢[ä'œn =¢¯€stN }ް-À¬SBŸ!´p +ã”Ð"H\U§„>FtCë’Ð „ir*ºчÝîë™KNHè%Fº¡À +ýb2r¸.q‰ébŠ™1€ ¹Ä£pP`…Þ›Šúe®l:‚ˆ2,(ÐBïH„˜£">(ÐBLDe.„Ð;"€²+(ÐBïˆpD(´zº"!bõUâJ'Iu +Áá( +¼Ð“Y• !ô³IÈFPåBlÝø“EKLC8Bœ +þA8qHäüá:!ÒË¡… Â#ûAØÌîTy !ˆxfìvA\¸?½Ö ®x }û!„ôè»ÖP„cì †~G$áy‚u?ú¹‚K8?Áð‰w@2Þ±'X„ž(PЄcÜ †€äFž`~)¤Xyä F8}’ŠŽ"NÁ¡ +LjŒrH´qu F9CbÃ179bB瀨£cnrP¶Ú81GTúœ2I€8Ò#*=iG¨MÇSzAéP•t´Ý6IÒ4 NÍÑ aKs-Wä®!Ò¶_  O°¥£fXŽ…€ìÒG2ĔfH@^áŒdˆíy݊G1DI ]¼ÄÇSâㆂ1ÁFˆqz@Á™`‹fXYiçÁ ¿XI© +Î|Õ,¨jk‚ œd™‘½¬ 6° ‹ÉsXC>°rHz€5EVFÔ +œåöÐ1‡ Ï àl sd Þ$Tê#ƄæãPê%ç1÷ï $ÆÇÜi:܀±¦;peu°ÃõfàB*ý@²ž1ðÿÔ0Æ €?S‡°ÖÛ3`)ә_‚ :S¢ÀqEX°µÃ5GreŽ ˜ ¹A8F†Xûª¥qB Õ* +3Cìuá,ùV…™!öªõا»Dsá ±GéÈ l +SCô“‘5^)^`&°}Zâgo†Z.ém‰¹‘tAalˆ=i¢0ò¡`±É•;õ,lr9£õ¸ã <— §¢ñ4.î΢AãrB:°ç½.9+¤q9`‰è£C×薈Ï: qå±B*×Èñ/á›È5ª%Rr_¨\czgÊñ•kÄÀž”4GæmŠÑÒ^è\#M1bbƒkœ)F<Ûep2ŨY.JzàšÁæ\;è©r<®µƒ‘Èä’Â])4áRY©Ã\®áÀx™dl.FÚÏ ŽË˜k ÅóƁ×þÙç^¤0áêßùYšF\}ƒ$Ÿšqõ«Š&Ɇ\}:h£hS®þÀ̒ñ¹È9Ô=-Lìsõ±l1LW·Ãe_ÍïMXá*¤][¼6ï‘®­-Ú²Ù¦p‡«Wî –M.KCv¹)\ã*䝱 ¾µÕ›\üÔê#Õµ½žØå2H¯F¤nÉÅ%³KÕ‡ìò­í>ôÁE̋÷W=¼ç¢®myÂeÇû—÷½||o\ûQë0ȋÕS_ŸÝ'×~ØîVêqº~êósûæ: Üî†ÃêêbW.W«ë§§Þ?r® +$ß¾Iß<È7ï¿ù$n? ùññãÍ×â>º¹òû¿{Ê>#Å;ñX@.òŸþðëÿ}÷ó¢øå‡Ÿ¿ûîO¿}÷ãßËÿÞ6¾··»Æ·w_ß|ïn?ÜÜíšïš½Ë‹ß½»½‰n¢ÿ¸ÝU~w¿ýÝ»»‡H¾ûå¯ç? ?ÿôýo¿ÿõ—C½7Kê§?ÿõçÿúãþºí槯ÞmÿïÓ?ˆÏ?þ(²ÝÙÛNýïßïš&r õÿɄñkendstream +endobj +200 0 obj +6310 +endobj +201 0 obj<>>>>>endobj +202 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +203 0 obj +31 +endobj +204 0 obj<>>>>>endobj +205 0 obj<>stream +xڅTKoâ0¾ó+F=Ôd P(Ç¥/!µÝl“V{ÈÅI&Å­c§¶býŽ ºl¥UN±?{¾ÇŒ?Œé‹`1éŠz°Jßn—-!­`ÍÂÌ3HËa¬±bŽÒ7BÌ Š"è Át²'•n¸£*»c¡5¨ ÔL¶L@‰¦Ð>>>>>endobj +208 0 obj<>stream +xڕÑÍRƒ0à=Oq–u6€@ÝùםÓ*¡nÜDHÛhI4 íèӛ@;Žé¢6Iîýr™óŒÝ"H2ÿÕmpKƒËéä**@—î.Ëó(mF÷ªîZ.-f[®·‚ï.軫MAÈP&“¡’®…QK»cš£3\´Lvlw¡ôŠIñÃiìšc©6µrÃk+”4×^ïñ¸ˆb„q¥Þ³ÿ_„˜k'z¥ü6–·GƒÖƒ’Äq' ÷*ã?Ùy–”8©´L6L7Ä5fŸýÿ¥º[óúã0•Smg°¬ß¾ð·¡£Øw’E9HZô¹=ßL©ªy‰òJÕ§òاâ›C’¦Ña}Sìϒ¢Àødô4x +~aT¡¯endstream +endobj +209 0 obj +296 +endobj +210 0 obj<>>>>>endobj +211 0 obj<>stream +xڝUMsÛ6½ëWìў‘}8Šul2É´‡ÔêXnsð"—"b`PŠþ}߂ÔG¨L2ÓÑE$w÷½}ûøw4¥ ~Sz7£ù‚òzô~=zóiIÓ%­KšMٜïîi]ÜLéŽV^ۨ햞!rM;ö;ÍûÛõW¤ÝÓt*iw]ÞÝü~’¥Ôu¥å•j"{j¼Ûé‚)K®Ï'WRåö+¦®®¥ç?ÿør…·wþ5dH¾Ío¨å‰ÏI+ï6†ëïÉuÁ þä<Xù@]È¢¹ͱJó£*7T©@Qۖ‹Äõeöv‘ѳ5ú•é³Î½ ®Œò–þѶpûþò³ÊŸÆ]ƒRÅ:© ^Óy6^!*[(_°/UΒ: ´X¼*å]Û4Î÷4StÈè7È·MRgÚ¨SÏ;íÚ`¤vJ…–Æ3€~Ïþ• #ÊGÑÿ>kÑqÀè<'€Ú…˜j+Ã6f}±Ùâ4ŒÀ×É=i2Úò‰6½ÜDþÉYsx¹•~W¨ý”{ÝÄ« !·õª©t^nÇéy¯c5ÔÑÕL¹Sßt§ÇrxnÚªwb¢¨l!¯ì–ÅŠ'<)\j“Ä®U„¸¿»=ôc”ÉU‹öXåCܝòrH%) Ú5ìՅ „\Ô§B—%{‰è„T•|‹–ÇTÖ¸æbÔÔÂëp_(ȁ¯Â¢šçšáÁÖykbFëJEHUo0“NËmt­#^ì`¤Z* 0ó6DˆÜ£Š]·GÄÞø’£Do•ăvŒ@f°kj›K+§H×,`ªŸc±Î‡ç ½â˜Ñ[é@,ÍXùl{FV¬$° †cë-†ñ´ÁÁW—’„Kß}‡l™‹ ÃBª¬ñj  + Å~kW´Fyqª$œO @õ¶#@àäÎ&Ò'6(¹,ù„+ß\zž>>>>>endobj +214 0 obj<>stream +xڍWÁRÜ8½ó}$UŒa€r !,¤HílÆ©½pÑÈ2£Œ-9’ŒwòõûZ²=ŒC¨­Pa<’ZÝï½~m~ÌéÿætvÁ?²>¸ÎŽoßÓüìŠòk——ÙåÅa¾V”+¹6¶²OÛwùwl<§ù~[,I{Z ¯ +jkHRµrOÚ<ѽ ÊÈa +á +’¢ª°3 ü¸¸pÚÞ¾p6Xi«#²Žî‹Œÿ£µ@|¥ '«çgÙ)_­ê•±V[*ìOe<ْŽ¥²(ÆÏ^¹güª…iK!Cë”óGqG§« +±É·Mc]HÁ87£þ ôEKg½-Ãäæ´)l‡ëåDLÜo}PuÖï;½ÈÎy'_¨RåIì hú*©D•ÍP;Šì²Áo$*"|q‘¾Û•ß«Ç6A[”[鍢ZZLôú§:"§¼­ZޚŠõ–o ëŒø ˆ¼³Äܐpá¬%H,-/U–9Û2%–aÜ£.ØÉÕ}ŽžÖ­)œ*<Ÿ kÛz¤ªuÅxtb›Ñ7k°ˆé^æ°¶Â])Q!óž!”Ry?¹UZëF´@¥ØÕ­ŒtÛ&=×bÃÀêBêV®©¶ô+ Qì¸pCâÂVƒ_#â¯ÄV¡Tâ¶á£»-ä1ËYH¹Æsúû +¿ËóÅuk<† QêÔª×-§ÒIAFùG@K’WÀ ·ô¬U‡Îm D"IøÜzÒb¨Ó×¼²Sר0­¿^­]Ìnåp¡rSL¢#€Êg]DÙK[7• +Š©<žg'£à¬cë0Òawì0È ™1ùÂÖB#a7Ikr’õ‚ÈèF?)^ •?,_Hc´ñ,t%V•BT¶ìÄ,Ď³åä^®6KîøÒFÙ#ŸÑ»¿5ÏOėh‡T=XôíªÖ}hϰÒû¦ í¢vs؏˜ÑçhÈX"@©“¯ jþÑÂÜÚzŶ„KÖ0ɤ6Ž ¼×O† Û²Dø€l+áàkgš‡­o£GŒ*z|×§ÁNx-žÕè\k¥\h§Ãše[O=Œ»“͐ý’£õ‰£=¤m´êMWZ§Ãö->V¸Rù·çØè1hÐJÉÐSN£§mŒí '5!A¾} ƒƒ_܉»FA•{¶ÔÎOÇÌN‰Ckj7Ç8oU{«+Î÷·ÕöëÉ4X>õ½hšjh$–Ʀf"Ì,bQF÷fÒlææ©’çJ–æxW»¢Ù)µÉ^"1Ö§*“›‚%ɂè5—jÏhiëaìo„ˆ—õ)as¡ËÁps²6Ÿú +±^RQœSȳ9£¿xy‚osÈý‰3ꥵfAš‹ +¿ñÙT×BnTj¤B³3‰µý…p]³ü#‡èŒ6ÏèoßFdz©ô%z +Ä ¢«7-yHfÏaöIÖ5Wq=¢»ÅìχãÓáqqs;|d@Ï·øœ½Fõ8»+´+-PóR:݄xvw }ž ¹ß`H²‰[~KC’_ïø©hbœÉÅI¨ÎÒJ‡Z4½ú7›>]ºùA·JôN°‹oE°Fvè*XhDTÍ$Á4¾9abwÖm0œE|þ¬ÂvPØ$ÿÇÃM³´¸/<¾;¢ej™/€…ºÆKÙ&E~Àëeê<¬ßUC©ã›ToW½çççÙ{º¸ºJ6póõÃm}Å"—xÏí¸%¿yVǼ,‹ŠÏÒ©Ùåé :çïÎO®2þcâÕ?>åü$ŸQendstream +endobj +215 0 obj +1367 +endobj +216 0 obj<>>>>>endobj +217 0 obj<>stream +xڅUÁRÛ0½ç+¶¹4Ì$'![K)Óvh‡–0½p²«È’+ɘü}w%Û$¦°´»o÷½·â÷(…üIa=‡Å +x9ºØŒŽ¯Î!=MÎ`“ãÝj½NV°É&7Vj/,\Zù$¬;ÚüÂÈ%¤iŒ›-Îã²RÇ»›[àF;é<˜Œô«4V@.•§0W .sÉÁ`PÅ"IL•š«:/++%º{j¡ÓE2'è ¹±ðI4Jx?»aü‘Ù ®™ö‹ðÀt—Â=Òßm—ÀÏBbU_H×ö ™A>>>>>endobj +220 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041ѳT072PIÑp rt QÐUp VÎO+)O,JU-N-*VðMÌ+MÌÑ Éâ҅èхj2‰™šé™+€ùE™y%©E +.E™e@ Y×®@.s#­endstream +endobj +221 0 obj +124 +endobj +222 0 obj<>>>>>endobj +223 0 obj<>stream +xڕSÁrÚ0½óÛCgÈ ¸6PÀ=¦CŽZœž¸{‹Ê’#Édü÷ݕpÒ¤i;\¬•Þ¾·ï-“ Rúe°YÀr e;¹-&îrÈr(jX¤«$ƒõfE5]ÀîÔà„½•Úóá08íMq&Ü +²Œqóœ/Wi°E#”èßïÔÞ\dE“ñM7N ßá8Ðô +ªîu¯éñ&Lp‹ö*þ„°¿CºÑÏÒ´-á]…¹Î/ ¦Ø–Ra-zå¹éΖɂu_£Ã#õ§439Íu5Œ¶¬£ýâ‚ñÂh$ \;÷΃F¬ÝÐá§Q}ÎD5¯É3é¨!ãÃ{P]ªE‹°ûRì¾½Ù +†Ž>û_í¿w öº¢õðl$Ã/»ÃC90uèèèÂbéíÔ¥ê+Î`oœ?”Vv>D)[ñ€ñ9¥Â«,”¢~ÛçÇÌjkZêèhb¢ë”,…—F;}ê÷\I3xjdÙà…#"ݤ‚îõµ$áïâÌۗÍÒ4Žü׿æj›&9Aèí†Ï»bòuòž5Ùendstream +endobj +224 0 obj +504 +endobj +225 0 obj<>>>/Annots 12 0 R>>endobj +226 0 obj<>stream +xÚ­VmoÓ0þÞ_qB* ÍÚõi lð([ø^â4ǶӪÿž;;I·ve›„6uss/Ï=÷Ü9 Œð'ñ”~³jð1¼»^@rÏ!-ðÙt6‹§æÃe©µj VF(Ç͛ôO I‚i4^Ó¯LíÀî¬ã•…­J¶áPiÃÁ•LVê؆ Éî$>Òø”Cc¹‰!-¹í,dèuǁ9Dz’ç­-!À¼É8>§¼RgL¶‰a#B­™aRr ÚÆø¼Öƽ¥ó>³Þ Ê­¸Ûjó;nŸOã N5:cvÂ:ÐÅ=×á[ÂícZF--CY[ÇÜC®†éªb*ß/¨‚‚šÐWÓ—Ðá5„8Õåpõ-½ºy3"߮ȜEõèÚ ­ÀÖ<…à–øw°Ó l™rDãÃÂöå :_ÎY”÷a 'ò¬ÿ>kŒá"Ð}Љœ¬‘®o2²Ifí#ÄzÂ:”Yç¶çô>ˆV&G4ÿЉÛs!$W¬âO’­M‹qõ$Fó?@ˆVÿD¹Ÿß§'û–;G܎/|÷XíÉ1¾ÆÂ*e·«Q9¨J†Ò ÒŽ:‚¡ÃŽÕ66R@ + ƒ‚38\<·1|Ñ[¾¡æb\Áá@?NT˜q[råµJžÄi†ËcÑå£è~̝ÈÉ!މ™v:±æ#ݽ@@€ Do­‰j”ñQՍߌAºSÁ •§Ab6›±šÓÿ‘ôrvA§Šç‚]~˜ôýŽÕë'À³Õ‡ëقÒÝ1¼Ážßƒj=™Wé`ðö „>n>Ãd|Žé“Å ‹¬`2áßp’pKw š.æBx´F{B7ÌìPc5W91K#UöVþv\‡*g&ï}¨á9·™w(¡à4Î{ÈçE<;ÀùÐŬûÒZô˒ՄwìÙ[Zëa|4‰!@?Œ«V™ð§HÔHÁR׸ ONãGíÊç->êè³{oÃÝ|œº¡9¸°3]ïüÝç5øBq+PMe¾ÄGvÖá~{õOëšz(m*Û]Ëô«ZéGnb)™CÁ´{ +Å¥aÍÝþA‹ãäý~jª¶¢íý¶ ±/SÓðƒu1oã$“I¼€é|NúɇŸn>\§Áòçênuá¶TçOK/Gø¾Õ0IîQðŠfç#ršÓwãÅ~5:ý‡#òcð7?òäendstream +endobj +227 0 obj +916 +endobj +228 0 obj<>>>/Annots 15 0 R>>endobj +229 0 obj<>stream +xÚ½UmoÓ:þÞ_qî$¤^©É’4kÚI|àŽ xk&>;©C Žk;«öï9ÇNË: +Ò@B•¢ÚçýyÎ9þ’B‚¿Š æ ¨»Éåäô*UœAÙÐÝbY@¹™þ[~™$¥)žì!R †.ªu/¸…HŖ’9þ¼4‡FH®XÇáò}yyCÖ§W+HÏâ%ùÐq4_Å9y»hyýU¨ÏàZ×F(Ç ¬sƒ…ÆèÎß_è®cj½Šo9P2 ¦Ožä©DÅ LFáTö=ZL¡Þ f +*ƒåpjÊmà‹®,Æeîõ-»ã`‡ªΡ&)ô”'&}¾‹÷±(Óÿ#˜Q*ßًƚ£öj£9äyVÅâ¨V¶×Jϊåqù^g^dË<;¬‡þ3_-3¤°T Psm6Èþ»‡­’òeóM ¥Ë9l[Q·žlt€€¹ ÞXíÄŸ¼ÞßIԟìÒ!Ò½Z=Ĩ?‚ã^rûõ w ôvÏÓî2Jã_€ñÁPØ Ý,‹»ÒÖ£O¼˜ +ƒPŠýZôñrþN[üz2ʟxõÓ ^ Uã°ß^¯ eëõ_“…]ï²¹6ÚéZË)’Vƒf2j8F3ØÄ[^a‹š;n|·i8ˆî)üe9Iâ·}Rúܼ‚l™Æ+Èά­CêŠøl>>>>>endobj +232 0 obj<>stream +xÚ-‹A‚0÷=Å[ê¢Ø/(ºT” J9@£ÅÔԂ´ÄëkÕ¼·šÌ<A|FH×ñ—ÛK¶(7 ‚ì@Y–l‘/äuv8ïJ Ž¢­4}^jÔh½=*å&eçòÎø¯áÿˆD„iNÉ +_PÆãn¨&Ì`5Š~0ÚGí(ى½5'-endstream +endobj +233 0 obj +133 +endobj +234 0 obj<>>>>>endobj +235 0 obj<>stream +xÚ¥TMÓ0½÷WŒVBJ¥&Û|4m‘¸ .,,$Üzq·1rlc»´Ý_Ï8N¶Ý²° ”S<3ï½y3ö÷Q Süb˜'æPµ£·åèöÝâ%”[HâY”B>Ï ¬ƒB(,5Ñ5Ük&,ÕðIY&…—ß°,ƒ8ve¡¯ Ólu¥eà T Q®¤¦¦ÒlC ؆‚U(="‰¢)„q²á >‰˜m:O>íÉ®žª  ’m‹,‘?ÇæfÑÂE¦(qé¾§‚jŸïÇçå¾ +[ɹ<8 ƒV¢?]É#œƒ=)lSnaË85gþ4JÜÄã”Óª«sÝњ(؝@‰@ùPȽ®è¥Ý„ZWüæxz¸éõ¡Ö›Ý…Àt¸vÀ½•LýzpréõáF„^k¸’9Ö:x\Á#ÕjÝà\‚´VË՗ó'w{nÙý^+iè?—š£p=Duú/旐.¶ÚÙqiöy1Ͼo¬ñó¶\yEñGá¦Ðoú6{ ­4Ì^)©mýe»†~úA¬ƒŠ ax¡ Û ¶ev=îgWõb“f‡Iî·{äóëk⽸¾*!|- è:XD³#F˜¨×.JçÇd¾lÛõø)á¥ÂgÙv„ÿ† #Wv͕Îò3×âñ}éºÃ»³ø›‡)›g˜8u©qìVåèóè'½G{®endstream +endobj +236 0 obj +539 +endobj +237 0 obj<>>>>>endobj +238 0 obj<>stream +xڝV]oë6 }ϯ 2 kØ³×Iô¡·í.ЮYí¾õE±•ă#y’Ü$ûõ#e;7‰=ܛ¢HE‘‡<<"ûÏÀ¿|Gôn_’Áï_Sð}H–LÝ¢ièN!ɮރh×ÉßxÁk.\݅õAØ€ß⸠áý +½';ßw£ä"]s=© ð½]0›l6ï×µo‹æãð î_ž}¯‹öÃ/¾âƒ²ä;sov¡ë7'¨¡¿ó½›‹Qžú |x:†œºQ„˜ãñ dàaõÞՉbB—Lq‘î»àÇVØð,g`ö˜jY©”_„õV–\õJÇP2úmÛ_óInûbÚãÏÆ|® +“Ï+UJÍ»¡­Õ)kó§ÓfjÅïYÉÒÜôðn͐6ö3Ǿg>>>>>endobj +241 0 obj<>stream +xÚ¥U[o›0~çWUª”Iƒa`„LêÚ¥Ó¤­k:i.˜ÀflfL³ýûÛi.R›¦©òás¾«IþxBüG§P´Þyî½»˜‰ƒò +ÏҌ˜¯åhδnÄtÍà\5‹Z Ö÷oò_¸!n܏'AjÆÊ +* B+É횼gŠrwëu•=éT#4+Aº4 ýӉ/·ÆÏ:¦ +&ô ÈN7R|pô!Lœ\ôà;éåÈ¡#¬ï`ŠD!T g‚¶ f—ùìf׋oÀÜü |`=,£š)T†ÎH²A;Ü`2±1ò–5"ýÛâÆèîJIÕoÜhtàH·÷ãȑn'þ™¶-…©TŠÆùQ¹/,H±9(}»tf­»Ã ãðõ‘“ùÓ¡¿²M~‰¡ÍÙ_ ߭ͧ/wެ•ä\.MR.”h×ñ(9¬$›¢3žûC›¾Ú;ô‹ÕLkªhæ{¸Â'_DQïUdÚ*ºf·+è™î-°X`|¡ AàWjˆHôh‹®Ð½&¿6ø6îâ[Ì£­ŽìõΦ’í3—ÈVææž·eïÒjúå}­X¯,[É#aL MR'ñÓÍNj|˜Þ^Ía.+½¤ŠÁmonÎ7*ÊͺO’·ü1þ¢îý£HÆ ¾ovˆÄæÁ,÷®½ÿMÚòendstream +endobj +242 0 obj +521 +endobj +243 0 obj<>>>>>endobj +244 0 obj<>stream +xڕVÁrÛ8 ½û+0éŒ3µTÉv§;=dÓtÚC»ÙF½åÂX°Å„U’ªã~}R²%M±I RHè—ÂdÆÏ¢ü› Þ~<…t![ÒÞlžòß|x…ÎÉj®@¸+„/¬de²[2™BšƒhrÏØà«6¥Pjã-j¶(ƒƒ`сÓ~¯&%Ké,èe8ndåÐĐiùmcÝc/E¿ø*Ҍ"ÔùE +—îýO¡|5â3Þ82rU<±ìt½]U¾Û¸ÑÎé²Ý];©+û.äœÀi`‰¨ÛÆî ¤üòT « XJ…•(.¾fßþl²‡ö`›m*[ìçø„Ñ®¸'ڕ7#êÃö¬ÝzM†TìUSbå@Z_®P> §ÖTdû Xá…ϤoOÆ´KKÚ@OŽË2>÷eMÆÆ¥!]nà’Còü£³ RŸ÷úêê uCÊP ÈрZ#Yën-]±SaՔ7hFp«oÀI§®‡m:Á÷Ù±z}ôÅnrá0†3eõÎýêù›7p‡›µ6yh’‚ê¯X˜»….=—JVŽH'”\È_˜¿\•;*ž,;ñ}Ï÷ ?eóÏ%çÿ_h…gù^j¥ôš‡FÛ8 êšøYX…ç=éý1û\¡¯”h;<„¿–Ú‹÷5šr¹·]Ë^GâÕ*ÌKdråE;…ò€ðÅôöÂԎ°—µa©ßŽmà~CJÖz/,.iüÓ ž' Ør¹éXöDPŸTÂ÷I;¯½þ¯‡½h•~‰{îâë#8ëµDš˜N)vÇÒZ*ÅÙ«](aY÷µB‡$aw~é… ;0Œ«ÍRKÁžïq’ô¿û‘‚ú)·¦æô¦>bÐ!™ŒgAòL2Õæ y÷4½éø1¿­Vg¶ý셤x4Ê{T–Iñ£rªÂf/W?4'I’܏§Ìc°ÜK.MîçÞ O ÇGûîGÔ©ð^0É1|`ZIúßí…/Åî—CÑl'Ÿ„ªÚ–oe£œ$ρÛí·ÝEìXªŸ]nZV~4hÝs£àÌß:?5¬ÆŒœ‘ʸo«çCÑàÃ1 íÝ7èÄÃI; 8'ú,(yF†cžºrF+ÓF7¦_)TøSZŠÒ’y ,NãSºfÍã>÷áÛÙÇ "8ÿ~yWzéÖ<å¿[4–n\}`Ø< +VÑÉ8a£tʋ“Ù$>†äo—µ‹lðÿà7öEÝendstream +endobj +245 0 obj +959 +endobj +246 0 obj<>>>>>endobj +247 0 obj<>stream +xÚ¥VQoÚ0~çWœ&M£R“:i0©m×v•ÖµƒôaR_ \‚Û$fNRÆ~ýÎq¡0iB +äøüù¾óٟu`ôq ï©Ó¤stN® m‚PÇüA‚Y÷(xî0°G¿|„x–„yg¯<.BcÊ„«ïÁÕHƒO®=Ðè,b±N‡¶¯‡só·_ýÝ-¶‡t«¨H0ÍAdÀ!-’ *•L4ƒ\‚þâé .fÍ 'ò©Œ¥Ò™’9υLmГ†2ŽåR¤ä|ãZÏ©:ëfE’p%þ`E2çi„°’ŧ8† –"ŸÃL„!*U9KöÙdÝ«²v<ÇÖR™íiÎ{%"‘òXƒºÌÓ³¼^êÙÎ&hbWA‡ÙŒ°õctŽëØ zßÀ@ÿt%­Æ{À.s7`öxÐ{[à²ÖËá¸ôú®YÁÎÊô«ä +µ0å\kü‰ºÒ–Tº†ï©ò}bm«Ê€[ª2àU¥–žk–èF!¦M5UîQ¯4]P‹n¢‡y>Q·dÀ-ð~A§®éc“SÑ}½ k-¥hkU#©q}âm«Æ€[ª1àýjw]ó¦’ñËʚ¬cìm÷RÁ|z¶UaÀ-Uð^ÞСmE9ÞñˆŽ ޔr›ÎD$›B.•H2ù^wyth´>*p;%x¿’¾c¶þåŠoí–í]±–òMDóÜJùëf¹Iò{íO€ +ÜR’ï9׆`ÎýöXåLç³ç"ËKƒ ó¼P¥}ÀS÷RŸöOG Cr¸MxôƯضÁ} oÌj‚³ª)uÀ‹’—3§ÙÀ4{m`ˆTÏ%ô\ǐÓ9Äâ÷’ÊÉ#²,9Æø*2"­ªiè5z¯¥ï¦ý_Þ^qüÓݳNE(°éݍ’”†_º½Ë˜ 绩‹¿PrVL‰„¿)È$æÓ‹n Ör.r$ Hóc —éZaî.DAìäðdõ oÖ8ü+L0^Ñzä˜fh)ƒÚò={žÇÌ|_Fç×Xpùø0†± ó%§®{̐¨îxZ˜Ë€eFY}—í6ÞWÊè©Ðt» çõ=Ú¤å g}_øÑù 3ü}µendstream +endobj +248 0 obj +839 +endobj +249 0 obj<>>>>>endobj +250 0 obj<>stream +xÚ-Ë»‚@„á~ŸbJ(À=BPJ¼-LTÍF„Èa‰¯¯¨™©þä{ +‚üŒDóoØ°X¤k+Pú1VK .Ý5I¶ù9CÖWö¥|Ôȓ2“z¸Ü +ïg¼?¢hŽI?À7$e;¶15ì]ã0i7Æ.ú +ÊàØ©ZÏhÏâ"Þɉ*ëendstream +endobj +251 0 obj +143 +endobj +252 0 obj<>>>/Annots 156 0 R>>endobj +253 0 obj<>stream +xÚ͛QsÜ6€ßý+ôØÎœ7")JâcãÔ¹v.­/v¦/y‘mÙÞvµòiw“Ëýú#HP"•dfj{Ó7Ÿ,AùÏ ËrýË*ž‰2»éN^_¼:WSÙÕ]ÆJ±âYYIýóêö‡«æzÓfý]vÖo÷ív¿ûñêϓŸ¯NòU®)ðƒÁ÷oa•¢Öj]&äªÀÁ&»„Ìä‡ûìչ̃G‚ž²»ڻ榅‡L9j±ZX‹­Žþ[´“(ÁP\êŸ]V±Ãa¨ ¥ÝUò pùe·o»lñ!·ÓÊÅJ†OÁyÃúýS;|Z·Ÿ¿mô‚­Ô=fWÆVµ~åºX•8X´+X“q-¡ßíMsètx/[Ô#j‹òJ[%àã<ò"6å:ڏ¦œüœe ß±¶¦þuíߓ¾fY—ZT¿#Ì9"µ5+ý]|;‹”ÓeЧÙeRé˜08œ‹a½Ý¯·÷Ë8ÐeJê&Àá4âbŸ §¯_±ÈWUHÃy¤EF¾x¸úÓ7™_JýaØAZB“•À•æ¡%<3aµg +ðƒÿ œn‰9Ú#hßaâóp~äõzì%pé1|Ë1éèÍG™•e™':¹,¯µ!°GP{ó°í7ýý—o›Q2>im/"æ,¤Y ô;–8 ÍY”vaøµ¿Þ}ÛLu3ŠàÚ]Vªq@Et¦9Û4»]»[ªúŽØ*1ƒh§Bú/M>1Ò <·«Áùz³o‡ƒèÚCu ÄŒ’—&ï–5,‰f@%¯¼´ÞËùÈB>bs<Î#îͰþ´hc‘Y:Ò$mÖB “ˆëZ‡‡Pf-”‰´ßÚýç~øK¯– yùhJÕTc@áZ”¥IDPGÚ¿'®EYلÄéÂÕáM}ðí,Rb…«ÃèµA…œF·YÌxê&ÓÌ~%œF֞ZÐ=eø€Ê¹õpQñ2ËG@¥ô¾' + Ñ–Ô _äQUä”Ân˜*iì ­ +.d»ŠÃu·ÞÓfõè°¹‡Mhð,œ/Ƶ¤Ý>òôíÆ¶iNqw=‘}u +ùüWsE¸%[,­Ù‹¹<æi½¡ƒe¦Îáë22ÛÌ®:g}OÎÑ$ó2Äã4â‚3©B”˜U!Ùy,® ‡:¢PqŒŽ°ÜÖ  +¤c¸)Ë/ÛÈ7çá 5BiÀq¾N*T|}ȋPÐ4'`{Iûu¿]*TøQl?cNaÂ얪Ò½NaŪN[b<¢mtÖ!ç‘÷î°Ù¯7-•'´m`wÏúÇõÒ΅×/còÜJ&«˜阜áŽí¡½ù+!!^U:“xœf U‰§ ”)"|Î3¯*!?> y6eÏ ðrßìÔê4¯†=mÈCäÝ =Ñ5ôõ5M}õ¶N År¾z§÷|ô¸ƒ©àUÏú®k¶·§ÿZoŽ`ªüïhE‡¨¨+[SAÄØ¢¢®mm‘¢o¢(Àã4ââ!êH6~Î×^Õёgâ'à9¦…èÈ3òPy)!:ÒÔWoëR,ç«ëå¹^ +C˜ +^õöz!ÙæÏÓ‰E«Ypt´BÑkd´ºsÖ³f{Ónèp:\Ùø0®vZF CO–L(²bƄ*µZNÚPÈäó—vˆûµ_ð+ޤ‹®È¾‚(*{¼¨_Çþ=©¯ ŠÚV ‚î+8¼Ùþ|;‹”X_Áaôv=186¶·ÍpK6¦—†ŽÚŒW-¡êe>MÔó—ÔŽ®z¡›þÂáÂ"GÑBfÙ­L24ƒ´^€Ò.ÇoÛm;4¢øÐî&xÎ#޶¨8®cþeãš*Fp†Ý¹ªp´h]¸èÂ9.•í¦½‰t­<¦=TáœOYßôê«ßKÌp(€¸«/Îhœ‰©ç§ÓóÔ5¬„;,! Ü«ö‡añæPþgkÑ Ík<Š€ƒP;"ƒ4Ç[PÑn„O„‚“Ã"ëóéõÔa큎C„ý>¬Û­®8u2Y¸­P¿L«–qÚ\¹ûPг#Ê\¥ö¹= ¸îtx'`óð–òŤ •?µ!  éu¿ ªþIü +{…v›»¾%ÛĞ:$5Ús,-¬€õwTÎQž/x.ç¾ÐŽCÆ­¯ +Ù¾ñ䬛ÇÅöæÓß+Œ†fËÌÒbGdhÖxÑ,y=Ÿ`Þ6x‚@$µüxÊžPé‡(@Ôûf{Oe‹c àPqdXyÚ°+…ÿ‡,@ÖEs¿Ø·{îZ(e%du;"££TØ»J[HF¾Iôß ¨”v“§î„õ"„¡Â^ëû‡ý¶Ýí–n½½PMÊDÄoõYãH©>¹twýáøÖ^>ß ”)µ§§nÛHÕ †{Ût]Cw‘ªÇóò+ + î¬ÈM‹eÂómâXär/ðöb Æ-x¤kà wg±ý/Ññh]¦à !@ã4¢èÝYñòûÝïþH¸»h"–«Xµ%òïùD݆°OG‹Kù@ªÌç¿( +XÔo‡îšìoxú¶Ž®g4+`iäZæéBSC’°¤³‡fhnà¾Q+y M,òÑA®V²–xA½¦¯¬QRÍ9-à@¿lo~pë ":•Lb3Ë “±B‹•«ú{âÒñmäø|'€À”Èt08 –›ŽgÃ'à¡@™PiyÚ°ä£YÃèt,8M¢BÓ@zÿN L0:4=eØTóßÌ ŒÏ'¾Œ Ӝû_Îc_.¾¯âs|F>ß ˆôŠÏÁl 0@Xb˜:ž£€‡ÈKSdqfò[ÀBw ¹ßºÅX=Ó5ÈX`Àîy*=íˆ + ¦òï*=G¾q\ÀGLŒVÀ5¿f vcÍӇ柿: +8Ú»f¸_/ºR>ÿõiVD¼ZM—–݈ôj5މÖný;sñºØ•!Î\<yïåOèXäj9üãUsù˄C»ÍJ.¿tdôy0ë!¢q¾H8c9®>•…ÂZ é숌J™c­tÓl"¹f"ږ” +ù(à€‘\3©Ã6ŽB˜p0ãî…ÎÏ ï³¢x•Z—Ï G¤GÞ¬þéöÏÃ.Ö&œ˜*à®wð'r“ÜWŸ@— „¡Âþy ۄ“º½¾RÏ`(€°?\é<öñGú +K=ô?C" +T u†§ å0ìêC + «ÙRµð¤ l97›@ÊO}y:«Ü]P7aÃE¬Ráx)<=VÝl,ñàÒº(’Žh'u[]Ìa(à®è7ûÃ`Ž¿¨ãÓn;B& + ó#”Ÿý@Ŭé̎{†tˆ¤bÖ×îLWJÎX(P¸ƒZª0iÃ%Ã|ôýذȢb¶úûw]ÌüK¡Wç5^°8e&ÉK…·"Þ¼ÿéü*;ÍÎ>\\f—ýÝþs3´Ù‡´SÞ5ÛC³}! ÍqZqóÛ­Ñÿ>ù?7±½endstream +endobj +254 0 obj +2716 +endobj +255 0 obj<>>>>>endobj +256 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS041ѳT072PIÑp rt QÐUp VÎO+)O,JU-N-*VðMÌ+MÌÑ Éâ҅èхjÊÌ º†pr¿%endstream +endobj +257 0 obj +102 +endobj +258 0 obj<>endobj +259 0 obj<>endobj +260 0 obj<>endobj +261 0 obj<>endobj +262 0 obj<>endobj +263 0 obj<>endobj +264 0 obj<>endobj +265 0 obj<>endobj +266 0 obj<>endobj +267 0 obj<>endobj +268 0 obj<>endobj +269 0 obj<>endobj +270 0 obj<>endobj +271 0 obj<>endobj +272 0 obj<>endobj +273 0 obj<>endobj +274 0 obj<>endobj +275 0 obj<>endobj +276 0 obj<>endobj +277 0 obj<>endobj +278 0 obj<>endobj +279 0 obj<>endobj +280 0 obj<>endobj +281 0 obj<>endobj +282 0 obj<>endobj +283 0 obj<>endobj +284 0 obj<>endobj +285 0 obj<>endobj +286 0 obj<>endobj +287 0 obj<>endobj +288 0 obj<>endobj +289 0 obj<>endobj +290 0 obj<>endobj +291 0 obj<>endobj +292 0 obj<>endobj +293 0 obj<>endobj +294 0 obj<>endobj +295 0 obj<>endobj +296 0 obj<>endobj +297 0 obj<>/Outlines 258 0 R/PageMode/UseOutlines/OpenAction[204 0 R/XYZ null null null]>>endobj +xref +0 298 +0000000000 65535 f +0000000015 00000 n +0000000218 00000 n +0000000279 00000 n +0000000353 00000 n +0000000431 00000 n +0000000508 00000 n +0000000587 00000 n +0000000663 00000 n +0000000744 00000 n +0000000802 00000 n +0000000907 00000 n +0000001012 00000 n +0000001043 00000 n +0000001094 00000 n +0000001179 00000 n +0000001203 00000 n +0000001307 00000 n +0000001412 00000 n +0000001517 00000 n +0000001622 00000 n +0000001727 00000 n +0000001830 00000 n +0000001933 00000 n +0000002037 00000 n +0000002142 00000 n +0000002247 00000 n +0000002352 00000 n +0000002457 00000 n +0000002562 00000 n +0000002667 00000 n +0000002772 00000 n +0000002877 00000 n +0000002982 00000 n +0000003087 00000 n +0000003192 00000 n +0000003297 00000 n +0000003402 00000 n +0000003505 00000 n +0000003608 00000 n +0000003712 00000 n +0000003817 00000 n +0000003922 00000 n +0000004027 00000 n +0000004132 00000 n +0000004237 00000 n +0000004342 00000 n +0000004447 00000 n +0000004552 00000 n +0000004657 00000 n +0000004762 00000 n +0000004867 00000 n +0000004972 00000 n +0000005077 00000 n +0000005182 00000 n +0000005287 00000 n +0000005392 00000 n +0000005497 00000 n +0000005602 00000 n +0000005707 00000 n +0000005812 00000 n +0000005917 00000 n +0000006022 00000 n +0000006127 00000 n +0000006232 00000 n +0000006337 00000 n +0000006442 00000 n +0000006547 00000 n +0000006652 00000 n +0000006757 00000 n +0000006862 00000 n +0000006967 00000 n +0000007072 00000 n +0000007177 00000 n +0000007282 00000 n +0000007385 00000 n +0000007488 00000 n +0000007592 00000 n +0000007697 00000 n +0000007802 00000 n +0000007907 00000 n +0000008012 00000 n +0000008117 00000 n +0000008222 00000 n +0000008327 00000 n +0000008432 00000 n +0000008537 00000 n +0000008642 00000 n +0000008747 00000 n +0000008852 00000 n +0000008957 00000 n +0000009062 00000 n +0000009167 00000 n +0000009272 00000 n +0000009377 00000 n +0000009482 00000 n +0000009587 00000 n +0000009692 00000 n +0000009797 00000 n +0000009902 00000 n +0000010007 00000 n +0000010113 00000 n +0000010219 00000 n +0000010325 00000 n +0000010431 00000 n +0000010537 00000 n +0000010643 00000 n +0000010749 00000 n +0000010855 00000 n +0000010961 00000 n +0000011067 00000 n +0000011173 00000 n +0000011279 00000 n +0000011385 00000 n +0000011491 00000 n +0000011597 00000 n +0000011703 00000 n +0000011809 00000 n +0000011915 00000 n +0000012021 00000 n +0000012127 00000 n +0000012233 00000 n +0000012339 00000 n +0000012445 00000 n +0000012551 00000 n +0000012657 00000 n +0000012763 00000 n +0000012869 00000 n +0000012975 00000 n +0000013081 00000 n +0000013187 00000 n +0000013293 00000 n +0000013399 00000 n +0000013505 00000 n +0000013611 00000 n +0000013717 00000 n +0000013823 00000 n +0000013929 00000 n +0000014035 00000 n +0000014141 00000 n +0000014247 00000 n +0000014353 00000 n +0000014459 00000 n +0000014565 00000 n +0000014671 00000 n +0000014777 00000 n +0000014883 00000 n +0000014989 00000 n +0000015095 00000 n +0000015201 00000 n +0000015307 00000 n +0000015413 00000 n +0000015519 00000 n +0000015625 00000 n +0000015731 00000 n +0000015837 00000 n +0000015943 00000 n +0000016997 00000 n +0000017031 00000 n +0000017065 00000 n +0000017576 00000 n +0000017625 00000 n +0000017674 00000 n +0000017723 00000 n +0000017772 00000 n +0000017821 00000 n +0000017870 00000 n +0000017919 00000 n +0000017968 00000 n +0000018017 00000 n +0000018066 00000 n +0000018115 00000 n +0000018164 00000 n +0000018213 00000 n +0000018262 00000 n +0000018311 00000 n +0000018360 00000 n +0000018409 00000 n +0000018458 00000 n +0000018507 00000 n +0000018556 00000 n +0000018605 00000 n +0000018654 00000 n +0000018703 00000 n +0000018752 00000 n +0000018801 00000 n +0000018850 00000 n +0000018899 00000 n +0000018948 00000 n +0000018997 00000 n +0000019046 00000 n +0000019095 00000 n +0000019144 00000 n +0000019193 00000 n +0000019242 00000 n +0000019291 00000 n +0000019340 00000 n +0000019389 00000 n +0000019618 00000 n +0000019770 00000 n +0000026151 00000 n +0000026173 00000 n +0000026286 00000 n +0000026388 00000 n +0000026408 00000 n +0000026539 00000 n +0000027300 00000 n +0000027321 00000 n +0000027461 00000 n +0000027828 00000 n +0000027849 00000 n +0000027989 00000 n +0000028903 00000 n +0000028924 00000 n +0000029064 00000 n +0000030502 00000 n +0000030524 00000 n +0000030664 00000 n +0000031556 00000 n +0000031577 00000 n +0000031690 00000 n +0000031885 00000 n +0000031906 00000 n +0000032046 00000 n +0000032621 00000 n +0000032642 00000 n +0000032805 00000 n +0000033792 00000 n +0000033813 00000 n +0000033976 00000 n +0000034861 00000 n +0000034882 00000 n +0000034995 00000 n +0000035199 00000 n +0000035220 00000 n +0000035369 00000 n +0000035979 00000 n +0000036000 00000 n +0000036158 00000 n +0000037202 00000 n +0000037223 00000 n +0000037363 00000 n +0000037955 00000 n +0000037976 00000 n +0000038125 00000 n +0000039155 00000 n +0000039176 00000 n +0000039334 00000 n +0000040244 00000 n +0000040265 00000 n +0000040378 00000 n +0000040592 00000 n +0000040613 00000 n +0000040768 00000 n +0000043555 00000 n +0000043577 00000 n +0000043690 00000 n +0000043863 00000 n +0000043884 00000 n +0000043939 00000 n +0000044044 00000 n +0000044188 00000 n +0000044291 00000 n +0000044396 00000 n +0000044561 00000 n +0000044669 00000 n +0000044784 00000 n +0000044889 00000 n +0000044997 00000 n +0000045105 00000 n +0000045221 00000 n +0000045319 00000 n +0000045485 00000 n +0000045602 00000 n +0000045721 00000 n +0000045845 00000 n +0000045970 00000 n +0000046120 00000 n +0000046261 00000 n +0000046370 00000 n +0000046522 00000 n +0000046661 00000 n +0000046791 00000 n +0000046915 00000 n +0000047051 00000 n +0000047178 00000 n +0000047301 00000 n +0000047417 00000 n +0000047566 00000 n +0000047695 00000 n +0000047832 00000 n +0000047962 00000 n +0000048087 00000 n +0000048190 00000 n +0000048327 00000 n +0000048432 00000 n +0000048571 00000 n +0000048705 00000 n +trailer +<> +startxref +48891 +%%EOF diff --git a/doc/sum.shtml b/doc/sum.shtml new file mode 100644 index 0000000000..4883760bf6 --- /dev/null +++ b/doc/sum.shtml @@ -0,0 +1,562 @@ + + + + + + + DRAFT - CUPS Software Users Manual + + + +

Preface

+ +This software users manual describes how to use the Common UNIX Printing +System ("CUPS") Version 1.0.0. + +

System Overview

+ +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +

This software users manual is organized into the following sections:

+ +
    +
  • 1 - Printing System Overview
  • +
  • 2 - Using the Printing System
  • +
  • 3 - Standard Printer Options
  • +
  • 4 - Checking the Status Via the Web
  • +
+ +

1 - Printing System Overview

+ +

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 MacOS, UNIX has no standard interface or +system in place for supporting printers. Among the solutions previously +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 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. + +

The Common UNIX Printing System, or 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, or IPP. IPP has been embraced by dozens of printer +and printer server manufacturers, and will be supported by the next +Microsoft Windows operating system. + +

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 secure printing solution than older ones. + +

IPP is layered on top of the Hyper-Text Transport Protocol, or HTTP, +which is the basis of web servers on the Internet. This allows the user to +view documentation and status information on a printer or server using their +web browser. + +

CUPS provides a complete IPP/1.0-based printing system that provides Basic +authentication and domain or IP-based access control. Digest authentication +and TLS encryption will be available in future versions of CUPS. + +

Jobs

+ +

Each file 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. + +

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. Backend filters perform the most +important task of all - they send the filtered print data to the +printer. + +

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 Processors, or RIPs, that +convert PostScript or image files into bitmaps that can be sent to a +raster printer. + +

CUPS provides backends for printing over parallel and serial ports, +and over the network via the JetDirect (AppSocket), Server Message +Block, and Line Printer Daemon protocols. + +

Printer Drivers

+ +

Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes a sample printer driver for Hewlett-Packard +LaserJet and DeskJet printers. While this driver does not generate +optimal output for different printer models, it does 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. If there is only one occurrence of a printer on a network, +then that printer can be accessed using its name alone. If more than one +printer exists with the same name, users must select the printer by specifying +which server to use (e.g. "printer@host1" or "printer@host2".) + +

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 +goes down! + +

2 - Using the Printing System

+ +

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) and Berkeley +(lpr) printing commands. To print a file to the default printer +on the system (or your only printer if you have only one) you just need to +type: + +

    +% lp filename ENTER
    +
+ +

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! + +

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 or serial port, +or available over the network. + +

To see a list of available printers, use the lpstat command: + +

    +% 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. + +

To print to a specific printer, use the "-d" option to the lp +command: + +

    +% lp -d printer filename ENTER
    +
+ +

or the "-P" option to 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 command allows you to pass printer options using the +"-o" option: + +

    +% lp -o landscape -o scaling=75 -o media=A4 filename.jpg
    +
+ +

The lpr command has no command-line option for printer options. + +

The available printer options vary depending on the printer. The standard +options are described in Chapter 3. + +

Printing Multiple Copies

+ +

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. To get collated copies +use the lp command with the "-o Collate=True" option: + +

    +% lp -n num-copies -o Collate=True filename ENTER
    +
+ +

Checking the Printer Status from the Command-Line

+ +

The lpstat command can be used to check for jobs that you +have submitted for printing: + +

    +% lpstat ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +
+ +

The jobs are listed in the order they will be printed. To see which files +and printers are active, use the "-p" option: + +

    +% lpstat -p ENTER
    +printer DeskJet now printing DeskJet-1.
    +
+ +

Or to show the jobs and the printers, use the "-o" and "-p" options: + +

    +% lpstat -o -p ENTER
    +Printer-1 johndoe 4427776
    +Printer-2 johndoe 15786
    +Printer-3 johndoe 372842
    +printer DeskJet now printing DeskJet-1.
    +
+ +

Checking the Printer Status from the Web

+ +

Since CUPS uses the Internet Printing Protocol, it is also a +full-featured 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! + +

Canceling a Print Job

+ +

The cancel command cancels a print job: + +

    +% cancel job-id ENTER
    +
+ +

The job-id is a 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 command. + +

General Options

+ +

The following options apply when printing all types of files. + +

Selecting the Media Size, Type, and Source

+ +

The "-o media=xyz" option sets the media size, type, and/or source: + +

    +% lp -o media=Letter filename ENTER
    +% lp -o media=Letter,MultiPurpose filename ENTER
    +% lp -o media=Letter,Transparency filename ENTER
    +% lp -o media=Letter,MultiPurpose,Transparency filename ENTER
    +
+ +

The available media sizes, types, and sources depend on the printer, but +most support the following options (case is 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. + +

Setting the Orientation

+ +

The "-o landscape" option will rotate the page 90 degrees to print in +landscape orientation: + +

    +% lp -o landscape filename ENTER
    +
+ +

Printing On Both Sides of the Paper

+ +

The "-o sides=two-sided-short" and "-o sides=two-sided-long" options will +enable duplexing on the printer (if the printer supports it.) The "two-sided-short" +option is suitable for landscape pages, while the "two-sided-long" option is +suitable for portrait pages: + +

    +% lp -o sides=two-sided-short filename ENTER
    +% lp -o sides=two-sided-long filename ENTER
    +
+ +

Selecting a Range of Pages

+ +

The "-o page-ranges=pages" option selects a range of pages for printing: + +

    +% lp -o page-ranges=1 filename ENTER
    +% lp -o page-ranges=1-4 filename ENTER
    +% lp -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-range" option. + +

To select the even or odd pages, use the "-o page-set=set" option: + +

    +% lp -o page-set=odd filename ENTER
    +% lp -o page-set=even filename ENTER
    +
+ +

Setting the Brightness

+ +

You can control the overall brightness of the printed output using the +"-o brightness=percent" option: + +

    +% lp -o brightness=120 filename ENTER
    +
+ +

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: + +

    +% lp -o gamma=1700 filename ENTER
    +
+ +

Values greater than 1000 will lighten the print, while values less +than 1000 will darken it. + +

Text Options

+ +

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: + +

    +% lp -o cpi=12 filename ENTER
    +
+ +

Setting the Number of Lines Per Inch

+ +

The "-o lpi=value" option sets the number of lines per inch: + +

    +% lp -o lpi=8 filename ENTER
    +
+ +

Setting the Number of Columns

+ +

The "-o columns=value" option sets the number of text columns: + +

    +% lp -o columns=2 filename ENTER
    +
+ +

Setting the Page Margins

+ +

Normally the page margins are set to the hard limits of the printer. To +adjust the page margins use the "-o page-left=value", "-o page-right=value", +"-o page-top=value", and "-o page-bottom=value" options: + +

    +% lp -o page-left=value filename ENTER
    +% lp -o page-right=value filename ENTER
    +% lp -o page-top=value filename ENTER
    +% lp -o page-bottom=value filename ENTER
    +
+ +

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: + +

    +% lp -o prettyprint filename ENTER
    +
+ +

Image Options

+ +

The following options apply when printing image files. + +

Scaling the Image

+ +

The "-o scaling=percent" and "-o ppi=value" options change the size of a +printed image: + +

    +% lp -o scaling=percent filename ENTER
    +% lp -o ppi=value filename ENTER
    +
+ +

The scaling percent 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. + +

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: + +

    +% lp -o hue=value filename ENTER
    +
+ +

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: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Originalhue=-45hue=45
RedPurpleYellow-orange
GreenYellow-greenBlue-green
YellowOrangeGreen-yellow
BlueSky-bluePurple
MagentaIndigoCrimson
CyanBlue-greenLight-navy-blue
+ +

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: + +

    +% lp -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. + + + diff --git a/doc/svd.html b/doc/svd.html new file mode 100644 index 0000000000..780f843022 --- /dev/null +++ b/doc/svd.html @@ -0,0 +1,149 @@ + + +CUPS Software Version Description + + + + + +


+

CUPS Software Version Description


+CUPS-SVD-1.0.0
+Easy Software Products
+Copyright 1997-1999, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Additions +
+
4 Changes +
+
A Glossary + +
+

1 Scope

+

1.1 Identification

+ This software version description document provides release +information for the Common UNIX Printing System ("CUPS") Version 1.0. +

1.2 System Overview

+ The Common UNIX Printing System provides a portable printing layer for + UNIX® 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 (IETF-IPP) as the basis for +managing print jobs and queues. The Line Printer Daemon (LPD, RFC1179), +Server Message Block (SMB), and AppSocket protocols are also supported +with reduced functionality.

+

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real world +applications under UNIX.

+

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers.

+

1.3 Document Overview

+

This Something Something Something document is organized into the +following sections:

+
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Additions
  • +
  • 4 - Changes
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+ The following CUPS documentation is referenced by this document: +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.0: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.0: CUPS Software Design Description
  • +
  • CUPS-SPM-1.0: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.0: CUPS Software Security Report
  • +
  • CUPS-STP-1.0: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.0.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+ The following non-CUPS documents are referenced by this document: +
    +
  • IEEE 1387.4, System Administration: Printing (draft)
  • +
  • IPP/1.0: Additional Optional Operations - Set 1
  • +
  • IPP/1.0: Encoding and Transport
  • +
  • IPP/1.0: Implementers Guide
  • +
  • IPP/1.0: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
+

3 Additions

+ Since this is the first release of CUPS, there are no additions to +report. +

4 Changes

+ Since this is the first release of CUPS, there are no changes to +report. +

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.
+
+

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 Printer 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
+
PCL
+
Page Control Language
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+ + diff --git a/doc/svd.pdf b/doc/svd.pdf new file mode 100644 index 0000000000..4491433eae Binary files /dev/null and b/doc/svd.pdf differ diff --git a/doc/svd.shtml b/doc/svd.shtml new file mode 100644 index 0000000000..1f9c34c2a2 --- /dev/null +++ b/doc/svd.shtml @@ -0,0 +1,167 @@ + + + + + + CUPS Software Version Description + + + +

Scope

+ +

Identification

+ +This software version description document provides release information for the +Common UNIX Printing System ("CUPS") Version 1.0. + +

System Overview

+ +The Common UNIX Printing System provides a portable printing layer for +UNIX® 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 (IETF-IPP) as the basis +for managing print jobs and queues. The Line Printer Daemon (LPD, +RFC1179), Server Message Block (SMB), and AppSocket protocols are also +supported with reduced functionality. + +

CUPS adds network printer browsing and PostScript Printer +Description ("PPD")-based printing options to support real +world applications under UNIX. + +

CUPS also includes a customized version of GNU GhostScript +(currently based off GNU GhostScript 4.03) and an image file RIP that +can be used to support non-PostScript printers. + +

Document Overview

+ +

This Something Something Something document is organized into the following +sections:

+ +
    +
  • 1 - Scope
  • +
  • 2 - References
  • +
  • 3 - Additions
  • +
  • 4 - Changes
  • +
  • A - Glossary
  • +
+ +

References

+ +

CUPS Documentation

+ +The following CUPS documentation is referenced by this document: + +
    +
  • CUPS-CMP-1.0: CUPS Configuration Management Plan +
  • CUPS-IDD-1.0: CUPS System Interface Design Description +
  • CUPS-SAM-1.0.x: CUPS Software Administrators Manual +
  • CUPS-SDD-1.0: CUPS Software Design Description +
  • CUPS-SPM-1.0: CUPS Software Programming Manual +
  • CUPS-SSR-1.0: CUPS Software Security Report +
  • CUPS-STP-1.0: CUPS Software Test Plan +
  • CUPS-SUM-1.0.x: CUPS Software Users Manual +
  • CUPS-SVD-1.0.x: CUPS Software Version Description +
+ +

Other Documents

+ +The following non-CUPS documents are referenced by this document: + +
    +
  • IEEE 1387.4, System Administration: Printing (draft) +
  • IPP/1.0: Additional Optional Operations - Set 1 +
  • IPP/1.0: Encoding and Transport +
  • IPP/1.0: Implementers Guide +
  • IPP/1.0: Model and Semantics +
  • RFC 1179, Line Printer Daemon Protocol +
+ +

Additions

+ +Since this is the first release of CUPS, there are no additions to report. + +

Changes

+ +Since this is the first release of CUPS, there are no changes to report. + +

Glossary

+ +

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. + +
+ +

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 Printer 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 + +
PCL +
Page Control Language + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
+ + + diff --git a/filter/Makefile b/filter/Makefile new file mode 100644 index 0000000000..bdf5892d29 --- /dev/null +++ b/filter/Makefile @@ -0,0 +1,150 @@ +# +# "$Id$" +# +# Filter makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +TARGETS = hpgltops texttops pstops imagetops imagetoraster \ + 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 +IMAGEOBJS = image-colorspace.o image-photocd.o image-sgilib.o \ + image-tiff.o image-gif.o image-png.o image-sgi.o image-zoom.o \ + image-jpeg.o image-pnm.o image-sun.o image.o +OBJS = $(HPGLOBJS) $(IMAGEOBJS) imagetops.o imagetoraster.o \ + common.o pstops.o rastertohp.o texttops.o textcommon.o + +# +# Make all targets... +# + +all: $(TARGETS) + +# +# Clean all object files... +# + +clean: + rm -f $(OBJS) $(TARGETS) $(LIBCUPSIMAGE) + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERROOT)/filter + $(CP) $(TARGETS) $(SERVERROOT)/filter + -$(MKDIR) $(LIBDIR) + $(CP) $(LIBCUPSIMAGE) $(LIBDIR) + -if test $(LIBCUPSIMAGE) != "libcupsimage.a"; then \ + $(LN) $(LIBCUPSIMAGE) `basename $(LIBCUPSIMAGE) .1`; \ + fi + +# +# hpgltops +# + +hpgltops: $(HPGLOBJS) common.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ $(HPGLOBJS) common.o $(LIBS) -lm +$(HPGLOBJS): hpgltops.h + +# +# libcupsimage.so.1, libcupsimage.sl.1 +# + +libcupsimage.so.1 libcupsimage.sl.1: $(IMAGEOBJS) ../Makedefs + echo Linking $@... + $(DSO) $@ $(IMAGEOBJS) $(DSOLIBS) -lm + -$(LN) $@ `basename $@ .1` + +# +# libcupsimage.a +# + +libcupsimage.a: $(IMAGEOBJS) ../Makedefs + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(IMAGEOBJS) + $(RANLIB) $@ + +$(IMAGEOBJS): image.h + +# +# imagetops +# + +imagetops: imagetops.o common.o $(LIBCUPSIMAGE) ../Makedefs \ + ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ imagetops.o common.o -L. -lcupsimage \ + $(IMGLIBS) $(LIBS) +imagetops: common.h image.h + +# +# imagetoraster +# + +imagetoraster: imagetoraster.o common.o $(LIBCUPSIMAGE) ../Makedefs \ + ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ imagetoraster.o common.o -L. -lcupsimage \ + $(IMGLIBS) $(LIBS) +imagetoraster: common.h image.h + +# +# pstops +# + +pstops: pstops.o common.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ pstops.o common.o $(LIBS) +pstops.o: common.h + +# +# rastertohp +# + +rastertohp: rastertohp.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ rastertohp.o $(LIBS) +rastertohp.o: ../cups/raster.h + +# +# texttops +# + +texttops: texttops.o textcommon.o common.o ../Makedefs \ + ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ texttops.o textcommon.o common.o $(LIBS) +texttops.o: common.h textcommon.h + +common.o: common.h +textcommon.o: textcommon.h common.h +$(OBJS): ../Makedefs ../cups/cups.h ../cups/ppd.h ../cups/language.h + +# +# End of "$Id$". +# diff --git a/filter/common.c b/filter/common.c new file mode 100644 index 0000000000..65ddc529e6 --- /dev/null +++ b/filter/common.c @@ -0,0 +1,252 @@ +/* + * "$Id$" + * + * Common filter routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * SetCommonOptions() - Set common filter options for media size, etc. + */ + +/* + * Include necessary headers... + */ + +#include "common.h" + + +/* + * Globals... + */ + +int Orientation = 0, /* 0 = portrait, 1 = landscape, etc. */ + Duplex = 0, /* Duplexed? */ + LanguageLevel = 1, /* Language level of printer */ + ColorDevice = 1; /* Do color text? */ +float PageLeft = 18.0f, /* Left margin */ + PageRight = 594.0f, /* Right margin */ + PageBottom = 36.0f, /* Bottom margin */ + PageTop = 756.0f, /* Top margin */ + PageWidth = 612.0f, /* Total page width */ + PageLength = 792.0f; /* Total page length */ + + +/* + * 'SetCommonOptions()' - Set common filter options for media size, etc. + */ + +ppd_file_t * /* O - PPD file */ +SetCommonOptions(int num_options, /* I - Number of options */ + cups_option_t *options, /* I - Options */ + int change_size) /* I - Change page size? */ +{ + float temp; /* Swapping variable */ + ppd_file_t *ppd; /* PPD file */ + ppd_size_t *pagesize; /* Current page size */ + const char *val; /* Option value */ + + + ppd = ppdOpenFile(getenv("PPD")); + + ppdMarkDefaults(ppd); + cupsMarkOptions(ppd, num_options, options); + + if ((pagesize = ppdPageSize(ppd, NULL)) != NULL) + { + PageWidth = pagesize->width; + PageLength = pagesize->length; + PageTop = pagesize->top; + PageBottom = pagesize->bottom; + PageLeft = pagesize->left; + PageRight = pagesize->right; + } + + if (ppd != NULL) + { + ColorDevice = ppd->color_device; + LanguageLevel = ppd->language_level; + } + + if ((val = cupsGetOption("landscape", num_options, options)) != NULL) + Orientation = 1; + + if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL) + { + /* + * Map IPP orientation values to 0 to 3: + * + * 3 = 0 degrees = 0 + * 4 = 90 degrees = 1 + * 5 = -90 degrees = 3 + * 6 = 180 degrees = 2 + */ + + Orientation = atoi(val) - 3; + if (Orientation >= 2) + Orientation ^= 1; + } + + if ((val = cupsGetOption("page-left", num_options, options)) != NULL) + { + switch (Orientation) + { + case 0 : + PageLeft = (float)atof(val); + break; + case 1 : + PageBottom = (float)atof(val); + break; + case 2 : + PageRight = PageWidth - (float)atof(val); + break; + case 3 : + PageTop = PageLength - (float)atof(val); + break; + } + } + + if ((val = cupsGetOption("page-right", num_options, options)) != NULL) + { + switch (Orientation) + { + case 0 : + PageRight = PageWidth - (float)atof(val); + break; + case 1 : + PageTop = PageLength - (float)atof(val); + break; + case 2 : + PageLeft = (float)atof(val); + break; + case 3 : + PageBottom = (float)atof(val); + break; + } + } + + if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL) + { + switch (Orientation) + { + case 0 : + PageBottom = (float)atof(val); + break; + case 1 : + PageRight = PageWidth - (float)atof(val); + break; + case 2 : + PageTop = PageLength - (float)atof(val); + break; + case 3 : + PageLeft = (float)atof(val); + break; + } + } + + if ((val = cupsGetOption("page-top", num_options, options)) != NULL) + { + switch (Orientation) + { + case 0 : + PageTop = PageLength - (float)atof(val); + break; + case 1 : + PageLeft = (float)atof(val); + break; + case 2 : + PageBottom = (float)atof(val); + break; + case 3 : + PageRight = PageWidth - (float)atof(val); + break; + } + } + + if (change_size) + switch (Orientation) + { + case 0 : /* Portait */ + break; + + case 1 : /* Landscape */ + temp = PageLeft; + PageLeft = PageBottom; + PageBottom = temp; + + temp = PageRight; + PageRight = PageTop; + PageTop = temp; + + temp = PageWidth; + PageWidth = PageLength; + PageLength = temp; + break; + + case 2 : /* Reverse Portrait */ + temp = PageWidth - PageLeft; + PageLeft = PageWidth - PageRight; + PageRight = temp; + + temp = PageLength - PageBottom; + PageBottom = PageLength - PageTop; + PageTop = temp; + break; + + case 3 : /* Reverse Landscape */ + temp = PageWidth - PageLeft; + PageLeft = PageWidth - PageRight; + PageRight = temp; + + temp = PageLength - PageBottom; + PageBottom = PageLength - PageTop; + PageTop = temp; + + temp = PageLeft; + PageLeft = PageBottom; + PageBottom = temp; + + temp = PageRight; + PageRight = PageTop; + PageTop = temp; + + temp = PageWidth; + PageWidth = PageLength; + PageLength = temp; + break; + } + + if ((val = cupsGetOption("sides", num_options, options)) != NULL && + strncmp(val, "two-", 4) == 0) + Duplex = 1; + else if ((val = cupsGetOption("Duplex", num_options, options)) != NULL && + strcmp(val, "DuplexNoTumble") == 0) + Duplex = 1; + else if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "Duplex", "DuplexTumble")) + Duplex = 1; + + return (ppd); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/common.h b/filter/common.h new file mode 100644 index 0000000000..16e9ac6cab --- /dev/null +++ b/filter/common.h @@ -0,0 +1,67 @@ +/* + * "$Id$" + * + * Common filter definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* + * Globals... + */ + +extern int Orientation, /* 0 = portrait, 1 = landscape, etc. */ + Duplex, /* Duplexed? */ + LanguageLevel, /* Language level of printer */ + ColorDevice; /* Do color text? */ +extern float PageLeft, /* Left margin */ + PageRight, /* Right margin */ + PageBottom, /* Bottom margin */ + PageTop, /* Top margin */ + PageWidth, /* Total page width */ + PageLength; /* Total page length */ + + +/* + * Prototypes... + */ + +extern ppd_file_t *SetCommonOptions(int num_options, cups_option_t *options, + int change_size); + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-attr.c b/filter/hpgl-attr.c new file mode 100644 index 0000000000..99a1b9fa57 --- /dev/null +++ b/filter/hpgl-attr.c @@ -0,0 +1,405 @@ +/* + * "$Id$" + * + * HP-GL/2 attribute processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * CR_color_range() - Set the range for color values. + * AC_anchor_corner() - Set the anchor corner. + * FT_fill_type() - Set the fill type or pattern. + * LA_line_attributes() - Set the line drawing attributes. + * LT_line_type() - Set the line type (style)... + * NP_number_pens() - Set the number of pens to be used. + * PC_pen_color() - Set the pen color... + * PW_pen_width() - Set the pen width. + * RF_raster_fill() - Set the raster fill pattern. + * SM_symbol_mode() - Set where symbols are drawn. + * SP_select_pen() - Select a pen for drawing. + * UL_user_line_type() - Set a user-defined line type. + * WU_width_units() - Set the units used for pen widths. + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" + + +/* + * 'CR_color_range()' - Set the range for color values. + */ + +void +CR_color_range(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + { + /* + * Default to 0 to 255 for all color values. + */ + + ColorRange[0][0] = 0.0; + ColorRange[0][1] = 255.0; + ColorRange[1][0] = 0.0; + ColorRange[1][1] = 255.0; + ColorRange[2][0] = 0.0; + ColorRange[2][1] = 255.0; + } + else if (num_params == 6) + { + /* + * Set the range based on the parameters... + */ + ColorRange[0][0] = params[0].value.number; + ColorRange[0][1] = params[1].value.number - params[0].value.number; + ColorRange[1][0] = params[2].value.number; + ColorRange[1][1] = params[3].value.number - params[2].value.number; + ColorRange[2][0] = params[4].value.number; + ColorRange[2][1] = params[5].value.number - params[4].value.number; + } + else + fprintf(stderr, "WARNING: HP-GL/2 \'CR\' command with invalid number of parameters (%d)!\n", + num_params); +} + + +/* + * 'AC_anchor_corner()' - Set the anchor corner. + */ + +void +AC_anchor_corner(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'FT_fill_type()' - Set the fill type or pattern. + * + * Note: + * + * This needs to be updated to support non-solid fill. + */ + +void +FT_fill_type(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0 || + params[0].value.number == 1 || + params[0].value.number == 2) + { + /**** SOLID PATTERN ****/ + } +} + + +/* + * 'LA_line_attributes()' - Set the line drawing attributes. + */ + +void +LA_line_attributes(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + int i; /* Looping var */ + + + if (num_params == 0) + { + Outputf("3.0 setmiterlimit\n"); + Outputf("0 setlinecap\n"); + Outputf("0 setlinejoin\n"); + } + else for (i = 0; i < (num_params - 1); i += 2) + switch ((int)params[i].value.number) + { + case 1 : + Outputf("%d setlinecap\n", + params[i + 1].value.number == 1 ? 0 : + params[i + 1].value.number == 4 ? 1 : 2); + break; + case 2 : + switch ((int)params[i + 1].value.number) + { + case 1 : + case 2 : + case 3 : + Outputf("0 setlinejoin\n"); + break; + case 5 : + Outputf("2 setlinejoin\n"); + break; + default : + Outputf("1 setlinejoin\n"); + break; + } + break; + case 3 : + Outputf("%f setmiterlimit\n", + 1.0 + 0.5 * (params[i + 1].value.number - 1.0)); + break; + } +} + + +/* + * 'LT_line_type()' - Set the line type (style)... + * + * Note: + * + * This needs to be updated to support line types. + */ + +void +LT_line_type(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'NP_number_pens()' - Set the number of pens to be used. + */ + +void +NP_number_pens(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + int i; /* Looping var */ + + + if (num_params == 0) + PenCount = 8; + else if (num_params == 1) + PenCount = (int)params[0].value.number; + else + fprintf(stderr, "WARNING: HP-GL/2 \'NP\' command with invalid number of parameters (%d)!\n", + num_params); + + PC_pen_color(0, NULL); + + for (i = 0; i <= PenCount; i ++) + Outputf("/W%d { DefaultPenWidth PenScaling mul setlinewidth } bind def\n", i); +} + + +/* + * 'PC_pen_color()' - Set the pen color... + */ + +void +PC_pen_color(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + int i; /* Looping var */ + static float standard_colors[8][3] = /* Standard colors for first 8 pens */ + { + { 1.0, 1.0, 1.0 }, /* White */ + { 0.0, 0.0, 0.0 }, /* Black */ + { 1.0, 0.0, 0.0 }, /* Red */ + { 0.0, 1.0, 0.0 }, /* Green */ + { 1.0, 1.0, 0.0 }, /* Yellow */ + { 0.0, 0.0, 1.0 }, /* Blue */ + { 1.0, 0.0, 1.0 }, /* Magenta */ + { 0.0, 1.0, 1.0 } /* Cyan */ + }; + + if (num_params == 0) + { + for (i = 0; i <= PenCount; i ++) + if (i < 8) + Outputf("/P%d { %.3f %.3f %.3f setrgbcolor } bind def\n", + i, standard_colors[i][0], + standard_colors[i][1], standard_colors[i][2]); + else + Outputf("/P%d { 0.0 0.0 0.0 setrgbcolor } bind def\n", i); + } + else if (num_params == 1) + { + i = (int)params[0].value.number; + + Outputf("/P%d { %.3f %.3f %.3f setrgbcolor } bind def\n", + i, standard_colors[i & 7][0], standard_colors[i & 7][1], + standard_colors[i & 7][2]); + } + else if (num_params == 4) + Outputf("/P%d { %.3f %.3f %.3f setrgbcolor } bind def\n", + (int)params[0].value.number, + (params[1].value.number - ColorRange[0][0]) / ColorRange[0][1], + (params[2].value.number - ColorRange[1][0]) / ColorRange[1][1], + (params[3].value.number - ColorRange[2][0]) / ColorRange[2][1]); + else + fprintf(stderr, "WARNING: HP-GL/2 \'PC\' command with invalid number of parameters (%d)!\n", + num_params); +} + + +/* + * 'PW_pen_width()' - Set the pen width. + */ + +void +PW_pen_width(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + int pen; /* Pen number */ + float w; /* Width value */ + + + if (WidthUnits == 0) + { + /* + * Metric... + */ + + if (num_params == 0) + w = 0.35f / 25.4f * 72.0f; + else + w = params[0].value.number / 25.4f * 72.0f; + } + else + { + /* + * Relative... + */ + + w = (float)hypot(PlotSize[0], PlotSize[1]) / 1016.0f * 72.0f; + + if (num_params == 0) + w *= 0.01f; + else + w *= params[0].value.number; + } + + if (num_params == 2) + Outputf("/W%d { %.1f PenScaling mul setlinewidth } bind def W%d\n", + (int)params[1].value.number, w, (int)params[1].value.number); + else if (num_params < 2) + { + /* + * Set width for all pens... + */ + + for (pen = 0; pen <= PenCount; pen ++) + Outputf("/W%d { %.1f PenScaling mul setlinewidth } bind def\n", + pen, w); + + Outputf("W%d\n", PenNumber); + } + else + fprintf(stderr, "WARNING: HP-GL/2 \'PW\' command with invalid number of parameters (%d)!\n", + num_params); +} + + +/* + * 'RF_raster_fill()' - Set the raster fill pattern. + * + * Note: + * + * This needs to be implemented. + */ + +void +RF_raster_fill(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'SM_symbol_mode()' - Set where symbols are drawn. + */ + +void +SM_symbol_mode(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'SP_select_pen()' - Select a pen for drawing. + */ + +void +SP_select_pen(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + PenNumber = 1; + else if (params[0].value.number <= PenCount) + PenNumber = (int)params[0].value.number; + else + fprintf(stderr, "WARNING: HP-GL/2 \'SP\' command with invalid number or value of parameters (%d, %d)!\n", + num_params, (int)params[0].value.number); + + Outputf("P%d W%d\n", PenNumber, PenNumber); +} + + +/* + * 'UL_user_line_type()' - Set a user-defined line type. + */ + +void +UL_user_line_type(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'WU_width_units()' - Set the units used for pen widths. + */ + +void +WU_width_units(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + WidthUnits = 0; + else if (num_params == 1) + WidthUnits = (int)params[0].value.number; + else + fprintf(stderr, "WARNING: HP-GL/2 \'WU\' command with invalid number of parameters (%d)!\n", + num_params); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-char.c b/filter/hpgl-char.c new file mode 100644 index 0000000000..75c72d8995 --- /dev/null +++ b/filter/hpgl-char.c @@ -0,0 +1,433 @@ +/* + * "$Id$" + * + * HP-GL/2 character processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * AD_define_alternate() - Define the alternate font. + * CF_character_fill() - Set whether or not to fill or outline + * characters. + * CP_character_plot() - Move the current pen position for the given + * number of columns and rows. + * DI_absolute_direction() - Set the direction vector for text. + * DR_relative_direction() - Set the relative direction vector for text. + * DT_define_label_term() - Set the label string terminator. + * DV_define_variable_path() - Define a path for text. + * ES_extra_space() - Set extra spacing (kerning) between characters. + * LB_label() - Display a label string. + * LO_label_origin() - Set the label origin. + * SA_select_alternate() - Select the alternate font. + * SD_define_standard() - Define the standard font... + * SI_absolute_size() - Set the absolute size of text. + * SL_character_slant() - Set the slant of text. + * SR_relative_size() - Set the relative size of text. + * SS_select_standard() - Select the standard font for text. + * TD_transparent_data() - Send transparent print data. + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" + + +/* + * 'AD_define_alternate()' - Define the alternate font. + */ + +void +AD_define_alternate(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + int i; /* Looping var */ + int typeface, /* Typeface number */ + posture, /* Posture number */ + weight; /* Weight number */ + float height; /* Height/size of font */ + + + /* + * Set default font attributes... + */ + + typeface = 48; + posture = 0; + weight = 0; + height = 11.5; + + /* + * Loop through parameter value pairs... + */ + + for (i = 0; i < (num_params - 1); i += 2) + switch ((int)params[i].value.number) + { + case 4 : + height = params[i + 1].value.number; + break; + case 5 : + posture = (int)params[i + 1].value.number; + break; + case 6 : + weight = (int)params[i + 1].value.number; + break; + case 7 : + typeface = (int)params[i + 1].value.number; + break; + } + + /* + * Define the font... + */ + + Outputf("/SA { /%s%s%s%s findfont %.1f scalefont setfont } def\n", + typeface == 48 ? "Courier" : "Helvetica", + (weight != 0 || posture != 0) ? "-" : "", + weight != 0 ? "Bold" : "", + posture != 0 ? "Oblique" : "", + height); + + CharHeight[1] = height; +} + + +/* + * 'CF_character_fill()' - Set whether or not to fill or outline characters. + */ + +void +CF_character_fill(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + CharFillMode = 0; + else + CharFillMode = (int)params[0].value.number; + + if (num_params == 2) + CharPen = (int)params[1].value.number; +} + + +/* + * 'CP_character_plot()' - Move the current pen position for the given number + * of columns and rows. + */ + +void +CP_character_plot(int num_params, + param_t *params) +{ + if (num_params < 2) + return; + + switch (Rotation) + { + case 0: + PenPosition[0] += params[0].value.number * 1.2f / CharHeight[CharFont]; + PenPosition[1] += params[1].value.number * CharHeight[CharFont]; + break; + case 90: + PenPosition[0] -= params[1].value.number * 1.2f / CharHeight[CharFont]; + PenPosition[1] += params[0].value.number * CharHeight[CharFont]; + break; + case 180: + PenPosition[0] -= params[0].value.number * 1.2f / CharHeight[CharFont]; + PenPosition[1] -= params[1].value.number * CharHeight[CharFont]; + break; + case 270: + PenPosition[0] += params[1].value.number * 1.2f / CharHeight[CharFont]; + PenPosition[1] -= params[0].value.number * CharHeight[CharFont]; + break; + } +} + + +/* + * 'DI_absolute_direction()' - Set the direction vector for text. + */ + +void +DI_absolute_direction(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + Outputf(CharFont == 0 ? "SS\n" : "SA\n"); + + if (num_params == 2) + Outputf("currentfont [ %f %f %f %f 0.0 0.0 ] makefont setfont\n", + params[0].value.number, -params[1].value.number, + params[1].value.number, params[0].value.number); +} + + +/* + * 'DR_relative_direction()' - Set the relative direction vector for text. + */ + +void +DR_relative_direction(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'DT_define_label_term()' - Set the label string terminator. + */ + +void +DT_define_label_term(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + StringTerminator = '\003'; + else + StringTerminator = params[0].value.string[0]; +} + + +/* + * 'DV_define_variable_path()' - Define a path for text. + */ + +void +DV_define_variable_path(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'ES_extra_space()' - Set extra spacing (kerning) between characters. + */ + +void +ES_extra_space(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'LB_label()' - Display a label string. + */ + +void +LB_label(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + char *s; /* Pointer into string */ + + + if (num_params == 0) + return; + + Outputf("gsave\n"); + Outputf("currentmiterlimit 1.0 setmiterlimit\n"); + Outputf("MP\n"); + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + + Outputf("("); + for (s = params[0].value.string; *s != '\0'; s ++) + if (strchr("()\\", *s) != NULL) + Outputf("\\%c", *s); + else + Outputf("%c", *s); + Outputf(") true charpath\n"); + + if (CharFillMode != 1) + Outputf("FI\n"); + if (CharFillMode == 1 || CharFillMode == 3) + Outputf("P%d ST\n", CharPen); + + Outputf("setmiterlimit\n"); + Outputf("grestore\n"); +} + + +/* + * 'LO_label_origin()' - Set the label origin. + */ + +void +LO_label_origin(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'SA_select_alternate()' - Select the alternate font. + */ + +void +SA_select_alternate(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; + + Outputf("SA\n"); + CharFont = 1; +} + + +/* + * 'SD_define_standard()' - Define the standard font... + */ + +void +SD_define_standard(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + int i; /* Looping var */ + int typeface, /* Typeface number */ + posture, /* Posture number */ + weight; /* Weight number */ + float height; /* Height/size of font */ + + + /* + * Set default font attributes... + */ + + typeface = 48; + posture = 0; + weight = 0; + height = 11.5; + + /* + * Loop through parameter value pairs... + */ + + for (i = 0; i < (num_params - 1); i += 2) + switch ((int)params[i].value.number) + { + case 4 : + height = params[i + 1].value.number; + break; + case 5 : + posture = (int)params[i + 1].value.number; + break; + case 6 : + weight = (int)params[i + 1].value.number; + break; + case 7 : + typeface = (int)params[i + 1].value.number; + break; + } + + /* + * Define the font... + */ + + Outputf("/SS { /%s%s%s%s findfont %.1f scalefont setfont } def\n", + typeface == 48 ? "Courier" : "Helvetica", + (weight != 0 || posture != 0) ? "-" : "", + weight != 0 ? "Bold" : "", + posture != 0 ? "Oblique" : "", + height); + + CharHeight[0] = height; +} + + +/* + * 'SI_absolute_size()' - Set the absolute size of text. + */ + +void +SI_absolute_size(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'SL_character_slant()' - Set the slant of text. + */ + +void +SL_character_slant(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'SR_relative_size()' - Set the relative size of text. + */ + +void +SR_relative_size(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'SS_select_standard()' - Select the standard font for text. + */ + +void +SS_select_standard(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; + + Outputf("SS\n"); + CharFont = 0; +} + + +/* + * 'TD_transparent_data()' - Send transparent print data. + */ + +void +TD_transparent_data(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-config.c b/filter/hpgl-config.c new file mode 100644 index 0000000000..729a67aa63 --- /dev/null +++ b/filter/hpgl-config.c @@ -0,0 +1,473 @@ +/* + * "$Id$" + * + * HP-GL/2 configuration routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * update_transform() - Update the page transformation matrix as needed. + * BP_begin_plot() - Start a plot... + * DF_default_values() - Set all state info to the default values. + * IN_initialize() - Initialize the plotter. + * IP_input_absolute() - Set P1 and P2 values for the plot. + * IR_input_relative() - Update P1 and P2. + * IW_input_window() - Setup an input window. + * PG_advance_page() - Eject the current page. + * PS_plot_size() - Set the plot size. + * RO_rotate() - Rotate the plot. + * RP_replot() - Replot the current page. + * SC_scale() - Set user-defined scaling. + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" + + +/* + * 'update_transform()' - Update the page transformation matrix as needed. + */ + +void +update_transform(void) +{ + float width, /* Plot width */ + height; /* Plot height */ + float page_width, /* Actual page width in points */ + page_length; /* Actual page length in points */ + float scaling; /* Scaling factor */ + + + /* + * Get the page and input window sizes... + */ + + width = IW2[0] - IW1[0]; + height = IW2[1] - IW1[1]; + + if (width == 0 || height == 0) + return; + + /* + * Scale the plot as needed... + */ + + if (FitPlot) + { + page_width = PageRight - PageLeft; + page_length = PageTop - PageBottom; + + if (Rotation == 0 || Rotation == 180) + { + scaling = page_width / width; + if (scaling > (page_length / width)) + scaling = page_length / width; + } + else + { + scaling = page_width / height; + if (scaling > (page_length / height)) + scaling = page_length / height; + } + } + else + { + page_width = PlotSize[0]; + page_length = PlotSize[1]; + + if (Rotation == 0 || Rotation == 180) + scaling = page_width / width; + else + scaling = page_width / height; + } + + /* + * Generate a new transformation matrix... + */ + + switch (Rotation) + { + case 0 : + Transform[0][0] = scaling; + Transform[0][1] = 0.0; + Transform[0][2] = -IW1[0] * scaling; + Transform[1][0] = 0.0; + Transform[1][1] = scaling; + Transform[1][2] = -IW1[1] * scaling; + break; + + case 90 : + Transform[0][0] = 0.0; + Transform[0][1] = -scaling; + Transform[0][2] = (height - IW1[0]) * scaling; + Transform[1][0] = scaling; + Transform[1][1] = 0.0; + Transform[1][2] = -IW1[1] * scaling; + break; + + case 180 : + Transform[0][0] = -scaling; + Transform[0][1] = 0.0; + Transform[0][2] = (height - IW1[0]) * scaling; + Transform[1][0] = 0.0; + Transform[1][1] = -scaling; + Transform[1][2] = (width - IW1[1]) * scaling; + break; + + case 270 : + Transform[0][0] = 0.0; + Transform[0][1] = scaling; + Transform[0][2] = -IW1[0] * scaling; + Transform[1][0] = -scaling; + Transform[1][1] = 0.0; + Transform[1][2] = (width - IW1[1]) * scaling; + break; + } + + PenScaling = Transform[0][0] + Transform[0][1]; + + if (PenScaling < 0.0) + PenScaling = -PenScaling; + + if (PageDirty) + printf("/PenScaling %.3f def W%d\n", PenScaling, PenNumber); +} + + +/* + * 'BP_begin_plot()' - Start a plot... + */ + +void +BP_begin_plot(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'DF_default_values()' - Set all state info to the default values. + */ + +void +DF_default_values(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; + + AC_anchor_corner(0, NULL); + AD_define_alternate(0, NULL); + SD_define_standard(0, NULL); + CF_character_fill(0, NULL); + DI_absolute_direction(0, NULL); + DT_define_label_term(0, NULL); + DV_define_variable_path(0, NULL); + ES_extra_space(0, NULL); + FT_fill_type(0, NULL); + IW_input_window(0, NULL); + LA_line_attributes(0, NULL); + LO_label_origin(0, NULL); + LT_line_type(0, NULL); + PA_plot_absolute(0, NULL); + PolygonMode = 0; + RF_raster_fill(0, NULL); + SC_scale(0, NULL); + SM_symbol_mode(0, NULL); + SS_select_standard(0, NULL); + TD_transparent_data(0, NULL); + UL_user_line_type(0, NULL); +} + + +/* + * 'IN_initialize()' - Initialize the plotter. + */ + +void +IN_initialize(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; + + DF_default_values(0, NULL); + PU_pen_up(0, NULL); + RO_rotate(0, NULL); + PS_plot_size(0, NULL); + WU_width_units(0, NULL); + PW_pen_width(0, NULL); + SP_select_pen(0, NULL); + + PenPosition[0] = PenPosition[1] = 0.0; +} + + +/* + * 'IP_input_absolute()' - Set P1 and P2 values for the plot. + */ + +void +IP_input_absolute(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + { + P1[0] = 0.0; + P1[1] = 0.0; + P2[0] = PlotSize[0] / 72.0f * 1016.0f; + P2[1] = PlotSize[1] / 72.0f * 1016.0f; + } + else if (num_params == 2) + { + P2[0] -= P1[0]; + P2[1] -= P1[1]; + P1[0] = params[0].value.number; + P1[1] = params[1].value.number; + P2[0] += P1[0]; + P2[1] += P1[1]; + } + else if (num_params == 4) + { + P1[0] = params[0].value.number; + P1[1] = params[1].value.number; + P2[0] = params[2].value.number; + P2[1] = params[3].value.number; + } + + IW1[0] = P1[0]; + IW1[1] = P1[1]; + IW2[0] = P2[0]; + IW2[1] = P2[1]; + + update_transform(); +} + + +/* + * 'IR_input_relative()' - Update P1 and P2. + */ + +void +IR_input_relative(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + { + P1[0] = PageLeft / 72.0f * 1016.0f; + P1[1] = PageBottom / 72.0f * 1016.0f; + P2[0] = PageRight / 72.0f * 1016.0f; + P2[1] = PageTop / 72.0f * 1016.0f; + } + else if (num_params == 2) + { + P2[0] -= P1[0]; + P2[1] -= P1[1]; + P1[0] = params[0].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f; + P1[1] = params[1].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f; + P2[0] += P1[0]; + P2[1] += P1[1]; + } + else if (num_params == 4) + { + P1[0] = params[0].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f; + P1[1] = params[1].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f; + P2[0] = params[2].value.number * PlotSize[0] / 72.0f * 1016.0f / 100.0f; + P2[1] = params[3].value.number * PlotSize[1] / 72.0f * 1016.0f / 100.0f; + } + + IW1[0] = P1[0]; + IW1[1] = P1[1]; + IW2[0] = P2[0]; + IW2[1] = P2[1]; + + update_transform(); +} + + +/* + * 'IW_input_window()' - Setup an input window. + */ + +void +IW_input_window(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + { + IW1[0] = P1[0]; + IW1[1] = P1[1]; + IW2[0] = P2[0]; + IW2[1] = P2[1]; + } + else if (num_params == 4) + { + IW1[0] = params[0].value.number; + IW1[1] = params[1].value.number; + IW2[0] = params[2].value.number; + IW2[1] = params[3].value.number; + } + + update_transform(); +} + + +/* + * 'PG_advance_page()' - Eject the current page. + */ + +void +PG_advance_page(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; + + if (PageDirty) + { + puts("grestore"); + puts("showpage"); + + PageDirty = 0; + } +} + + +/* + * 'PS_plot_size()' - Set the plot size. + */ + +void +PS_plot_size(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + switch (num_params) + { + case 0 : + if (Rotation == 0 || Rotation == 180) + { + PlotSize[0] = PageRight - PageLeft; + PlotSize[1] = PageTop - PageBottom; + } + else + { + PlotSize[0] = PageTop - PageBottom; + PlotSize[1] = PageRight - PageLeft; + } + break; + case 1 : + if (Rotation == 0 || Rotation == 180) + { + PlotSize[1] = 72.0f * params[0].value.number / 1016.0f; + PlotSize[0] = 0.75f * PlotSize[1]; + } + else + { + PlotSize[0] = 72.0f * params[0].value.number / 1016.0f; + PlotSize[1] = 0.75f * PlotSize[0]; + } + break; + case 2 : + if (Rotation == 0 || Rotation == 180) + { + PlotSize[0] = 72.0f * params[1].value.number / 1016.0f; + PlotSize[1] = 72.0f * params[0].value.number / 1016.0f; + } + else + { + PlotSize[0] = 72.0f * params[0].value.number / 1016.0f; + PlotSize[1] = 72.0f * params[1].value.number / 1016.0f; + } + break; + } + + /* + * This is required for buggy files that don't set the input window. + */ + + IP_input_absolute(0, NULL); +} + + +/* + * 'RO_rotate()' - Rotate the plot. + */ + +void +RO_rotate(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + Rotation = 0; + else + Rotation = (int)params[0].value.number; + + update_transform(); +} + + +/* + * 'RP_replot()' - Replot the current page. + */ + +void +RP_replot(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'SC_scale()' - Set user-defined scaling. + */ + +void +SC_scale(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + ScalingType = -1; + else if (num_params > 3) + { + Scaling1[0] = params[0].value.number; + Scaling2[0] = params[1].value.number; + Scaling1[1] = params[2].value.number; + Scaling2[1] = params[3].value.number; + + if (num_params > 4) + ScalingType = (int)params[4].value.number; + else + ScalingType = 0; + } + + update_transform(); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-input.c b/filter/hpgl-input.c new file mode 100644 index 0000000000..212dabc4ac --- /dev/null +++ b/filter/hpgl-input.c @@ -0,0 +1,232 @@ +/* + * "$Id$" + * + * HP-GL/2 input processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ParseCommand() - Parse an HPGL/2 command. + * FreeParameters() - Free all string parameter values. + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" +#include + +#define MAX_PARAMS 16384 + + +/* + * 'ParseCommand()' - Parse an HPGL/2 command. + * + * Returns the number of parameters seen or -1 on EOF. + */ + +int /* O - -1 on EOF, # params otherwise */ +ParseCommand(FILE *fp, /* I - File to read from */ + char *name, /* O - Name of command */ + param_t **params) /* O - Parameter list */ +{ + int num_params, /* Number of parameters seen */ + ch, /* Current char */ + done, /* Non-zero when the current command is read */ + i; /* Looping var */ + char buf[262144]; /* String buffer */ + static param_t p[MAX_PARAMS]; /* Parameter buffer */ + + + num_params = 0; + done = 0; + + do + { + while ((ch = getc(fp)) != EOF) + if (strchr(" \t\r\n,;", ch) == NULL) + break; + + if (ch == EOF) + return (-1); + + if (ch == 0x1b) + switch (getc(fp)) + { + case '.' : /* HP-GL/2 job control */ + i = getc(fp); + + if (strchr(")Z", i) != NULL) + { + /* + * 'Printer Off' command - look for next 'Printer On' command... + */ + + for (;;) + { + while ((i = getc(fp)) != EOF && i != 0x1b); + + if (i == EOF) + return (-1); + + if (getc(fp) != '.') + continue; + + if ((i = getc(fp)) == '(' || + i == 'Y') + break; + } + } + else if (strchr("@HIMNTI\003", i) != NULL) + { + while ((i = getc(fp)) != EOF && i != ':'); + } + break; + + default : /* HP RTL/PCL control */ + while ((i = getc(fp)) != EOF && !isupper(i)); + break; + } + } while (ch == 0x1b); + + name[0] = ch; + name[1] = getc(fp); + name[2] = '\0'; + + if (strcasecmp(name, "LB") == 0) + { + for (i = 0; (ch = getc(fp)) != StringTerminator; i ++) + buf[i] = ch; + buf[i] = '\0'; + p[num_params].type = PARAM_STRING; + p[num_params].value.string = strdup(buf); + num_params ++; + } + else if (strcasecmp(name, "SM") == 0) + { + buf[0] = getc(fp); + buf[1] = '\0'; + p[num_params].type = PARAM_STRING; + p[num_params].value.string = strdup(buf); + num_params ++; + } + else if (strcasecmp(name, "DT") == 0) + { + if ((buf[0] = getc(fp)) != ';') + { + buf[1] = '\0'; + p[num_params].type = PARAM_STRING; + p[num_params].value.string = strdup(buf); + num_params ++; + } + } + else if (strcasecmp(name, "PE") == 0) + { + for (i = 0; i < (sizeof(buf) - 1); i ++) + if ((buf[i] = getc(fp)) == ';') + break; + + buf[i] = '\0'; + p[num_params].type = PARAM_STRING; + p[num_params].value.string = strdup(buf); + num_params ++; + } + + while (!done) + switch (ch = getc(fp)) + { + case ',' : + case ' ' : + case '\n' : + case '\r' : + case '\t' : + break; + + case '\"' : + fscanf(fp, "%[^\"]\"", buf); + if (num_params < MAX_PARAMS) + { + p[num_params].type = PARAM_STRING; + p[num_params].value.string = strdup(buf); + num_params ++; + }; + break; + + case '-' : + case '+' : + ungetc(ch, fp); + fscanf(fp, "%f", &(p[num_params].value.number)); + if (num_params < MAX_PARAMS) + { + p[num_params].type = PARAM_RELATIVE; + num_params ++; + } + break; + case '0' : + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + case '.' : + ungetc(ch, fp); + fscanf(fp, "%f", &(p[num_params].value.number)); + if (num_params < MAX_PARAMS) + { + p[num_params].type = PARAM_ABSOLUTE; + num_params ++; + } + break; + default : + ungetc(ch, fp); + done = 1; + break; + } + + *params = p; + return (num_params); +} + + +/* + * 'FreeParameters()' - Free all string parameter values. + */ + +void +FreeParameters(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameter values */ +{ + int i; /* Looping var */ + + + for (i = 0; i < num_params; i ++) + if (params[i].type == PARAM_STRING) + free(params[i].value.string); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-main.c b/filter/hpgl-main.c new file mode 100644 index 0000000000..9c460985f5 --- /dev/null +++ b/filter/hpgl-main.c @@ -0,0 +1,255 @@ +/* + * "$Id$" + * + * HP-GL/2 filter main entry for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for HP-GL/2 filter. + * compare_names() - Compare two command names. + */ + +/* + * Include necessary headers... + */ + +/*#define DEBUG*/ +#define _HPGL_MAIN_C_ +#include "hpgltops.h" + + +/* + * HP-GL/2 command table... + */ + +typedef struct +{ + char name[4]; /* Name of command */ + void (*func)(int, param_t *); /* Function to call */ +} name_t; + +static name_t commands[] = +{ + { "BP", BP_begin_plot }, + { "DF", DF_default_values }, + { "IN", IN_initialize }, + { "IP", IP_input_absolute }, + { "IR", IR_input_relative }, + { "IW", IW_input_window }, + { "PG", PG_advance_page }, + { "RO", RO_rotate }, + { "RP", RP_replot }, + { "SC", SC_scale }, + { "AA", AA_arc_absolute }, + { "AR", AR_arc_relative }, + { "AT", AT_arc_absolute3 }, + { "CI", CI_circle }, + { "PA", PA_plot_absolute }, + { "PD", PD_pen_down }, + { "PE", PE_polyline_encoded }, + { "PR", PR_plot_relative }, + { "PS", PS_plot_size }, + { "PU", PU_pen_up }, + { "RT", RT_arc_relative3 }, + { "EA", EA_edge_rect_absolute }, + { "EP", EP_edge_polygon }, + { "ER", ER_edge_rect_relative }, + { "EW", EW_edge_wedge }, + { "FP", FP_fill_polygon }, + { "PM", PM_polygon_mode }, + { "RA", RA_fill_rect_absolute }, + { "RR", RR_fill_rect_relative }, + { "WG", WG_fill_wedge }, + { "AD", AD_define_alternate }, + { "CF", CF_character_fill }, + { "CP", CP_character_plot }, + { "DI", DI_absolute_direction }, + { "DR", DR_relative_direction }, + { "DT", DT_define_label_term }, + { "DV", DV_define_variable_path }, + { "ES", ES_extra_space }, + { "LB", LB_label }, + { "LO", LO_label_origin }, + { "SA", SA_select_alternate }, + { "SD", SD_define_standard }, + { "SI", SI_absolute_size }, + { "SL", SL_character_slant }, + { "SR", SR_relative_size }, + { "SS", SS_select_standard }, + { "TD", TD_transparent_data }, + { "AC", AC_anchor_corner }, + { "FT", FT_fill_type }, + { "LA", LA_line_attributes }, + { "LT", LT_line_type }, + { "NP", NP_number_pens }, + { "PC", PC_pen_color }, + { "CR", CR_color_range }, + { "PW", PW_pen_width }, + { "RF", RF_raster_fill }, + { "SM", SM_symbol_mode }, + { "SP", SP_select_pen }, + { "UL", UL_user_line_type }, + { "WU", WU_width_units } +}; +#define NUM_COMMANDS (sizeof(commands) / sizeof(name_t)) + + +/* + * Local functions... + */ + +static int compare_names(const void *p1, const void *p2); + + +/* + * 'main()' - Main entry for HP-GL/2 filter. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + FILE *fp; /* Input file */ + ppd_file_t *ppd; /* PPD file */ + int num_params; /* Number of parameters */ + param_t *params; /* Command parameters */ + name_t *command, /* Command */ + name; /* Name of command */ + int num_options; /* Number of print options */ + cups_option_t *options; /* Print options */ + const char *val; /* Option value */ + int shading; /* -1 = black, 0 = grey, 1 = color */ + float penwidth; /* Default pen width */ + + + if (argc < 6 || argc > 7) + { + fputs("ERROR: hpgltops job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + fp = stdin; + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file - "); + return (1); + } + } + + /* + * Process command-line options and write the prolog... + */ + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + if ((ppd = SetCommonOptions(num_options, options, 1)) != NULL) + ppdClose(ppd); + + shading = 1; + penwidth = 1.0; + + if ((val = cupsGetOption("blackplot", num_options, options)) != NULL) + shading = 0; + + if ((val = cupsGetOption("fitplot", num_options, options)) != NULL) + FitPlot = 1; + + if ((val = cupsGetOption("penwidth", num_options, options)) != NULL) + penwidth = (float)atof(val); + + /* + * Write the PostScript prolog and initialize the plotting "engine"... + */ + + OutputProlog(argv[3], argv[2], shading, penwidth); + + IP_input_absolute(0, NULL); + + /* + * Sort the command array... + */ + + qsort(commands, NUM_COMMANDS, sizeof(name_t), + (int (*)(const void *, const void *))compare_names); + + /* + * Read commands until we reach the end of file. + */ + + while ((num_params = ParseCommand(fp, name.name, ¶ms)) >= 0) + { +#ifdef DEBUG + { + int i; + fprintf(stderr, "DEBUG: %s(%d)", name.name, num_params); + for (i = 0; i < num_params; i ++) + if (params[i].type == PARAM_STRING) + fprintf(stderr, " \'%s\'", params[i].value.string); + else + fprintf(stderr, " %f", params[i].value.number); + fputs("\n", stderr); + } +#endif /* DEBUG */ + + if ((command = bsearch(&name, commands, NUM_COMMANDS, sizeof(name_t), + (int (*)(const void *, const void *))compare_names)) != NULL) + (*command->func)(num_params, params); + + FreeParameters(num_params, params); + } + + OutputTrailer(); + + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * 'compare_names()' - Compare two command names. + */ + +static int /* O - Result of strcasecmp() on names */ +compare_names(const void *p1, /* I - First name */ + const void *p2) /* I - Second name */ +{ + return (strcasecmp(((name_t *)p1)->name, ((name_t *)p2)->name)); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-polygon.c b/filter/hpgl-polygon.c new file mode 100644 index 0000000000..f16f8649d2 --- /dev/null +++ b/filter/hpgl-polygon.c @@ -0,0 +1,380 @@ +/* + * "$Id$" + * + * HP-GL/2 polygon routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * EA_edge_rect_absolute() - Draw a rectangle. + * EP_edge_polygon() - Stroke the edges of a polygon. + * ER_edge_rect_relative() - Draw a rectangle relative to the current + * EW_edge_wedge() - Draw a pie wedge. + * FP_fill_polygon() - Fill a polygon. + * PM_polygon_mode() - Set the polygon drawing mode. + * RA_fill_rect_absolute() - Fill a rectangle. + * RR_fill_rect_relative() - Fill a rectangle relative to the current + * WG_fill_wedge() - Fill a pie wedge. + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" + + +/* + * 'EA_edge_rect_absolute()' - Draw a rectangle. + */ + +void +EA_edge_rect_absolute(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y; /* Transformed coordinates */ + + + if (num_params < 2) + return; + + x = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + Transform[0][2]; + y = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + Transform[1][2]; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + Outputf("%.3f %.3f LI\n", PenPosition[0], y); + Outputf("%.3f %.3f LI\n", x, y); + Outputf("%.3f %.3f LI\n", x, PenPosition[1]); + + Outputf("CP\n"); + if (!PolygonMode) + Outputf("ST\n"); +} + + +/* + * 'EP_edge_polygon()' - Stroke the edges of a polygon. + */ + +void +EP_edge_polygon(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; + + Outputf("ST\n"); +} + + +/* + * 'ER_edge_rect_relative()' - Draw a rectangle relative to the current + * pen position. + */ + +void +ER_edge_rect_relative(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y; /* Transformed coordinates */ + + + if (num_params < 2) + return; + + x = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + PenPosition[0]; + y = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + PenPosition[1]; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + Outputf("%.3f %.3f LI\n", PenPosition[0], y); + Outputf("%.3f %.3f LI\n", x, y); + Outputf("%.3f %.3f LI\n", x, PenPosition[1]); + + Outputf("CP\n"); + if (!PolygonMode) + Outputf("ST\n"); +} + + +/* + * 'EW_edge_wedge()' - Draw a pie wedge. + */ + +void +EW_edge_wedge(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y; /* Transformed coordinates */ + float start, end, /* Start and end of arc */ + theta, /* Current angle */ + dt, /* Step between points */ + radius; /* Radius of arc */ + + + if (num_params < 3) + return; + + radius = params[0].value.number; + start = params[1].value.number; + end = start + params[2].value.number; + + if (num_params > 3) + dt = (float)fabs(params[3].value.number); + else + dt = 5.0f; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + + if (start < end) + for (theta = start + dt; theta < end; theta += dt) + { + x = (float)(PenPosition[0] + + radius * cos(M_PI * theta / 180.0) * Transform[0][0] + + radius * sin(M_PI * theta / 180.0) * Transform[0][1]); + y = (float)(PenPosition[1] + + radius * cos(M_PI * theta / 180.0) * Transform[1][0] + + radius * sin(M_PI * theta / 180.0) * Transform[1][1]); + + Outputf("%.3f %.3f LI\n", x, y); + } + else + for (theta = start - dt; theta > end; theta -= dt) + { + x = (float)(PenPosition[0] + + radius * cos(M_PI * theta / 180.0) * Transform[0][0] + + radius * sin(M_PI * theta / 180.0) * Transform[0][1]); + y = (float)(PenPosition[1] + + radius * cos(M_PI * theta / 180.0) * Transform[1][0] + + radius * sin(M_PI * theta / 180.0) * Transform[1][1]); + + Outputf("%.3f %.3f LI\n", x, y); + } + + x = (float)(PenPosition[0] + + radius * cos(M_PI * end / 180.0) * Transform[0][0] + + radius * sin(M_PI * end / 180.0) * Transform[0][1]); + y = (float)(PenPosition[1] + + radius * cos(M_PI * end / 180.0) * Transform[1][0] + + radius * sin(M_PI * end / 180.0) * Transform[1][1]); + Outputf("%.3f %.3f LI\n", x, y); + + Outputf("CP\n"); + if (!PolygonMode) + Outputf("ST\n"); +} + + +/* + * 'FP_fill_polygon()' - Fill a polygon. + */ + +void +FP_fill_polygon(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; + + Outputf("FI\n"); +} + + +/* + * 'PM_polygon_mode()' - Set the polygon drawing mode. + */ + +void +PM_polygon_mode(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0 || + params[0].value.number == 0) + { + Outputf("MP\n"); + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + PolygonMode = 1; + } + else if (params[0].value.number == 2) + PolygonMode = 0; +} + + +/* + * 'RA_fill_rect_absolute()' - Fill a rectangle. + */ + +void +RA_fill_rect_absolute(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y; /* Transformed coordinates */ + + + if (num_params < 2) + return; + + x = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + Transform[0][2]; + y = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + Transform[1][2]; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + Outputf("%.3f %.3f LI\n", PenPosition[0], y); + Outputf("%.3f %.3f LI\n", x, y); + Outputf("%.3f %.3f LI\n", x, PenPosition[1]); + + Outputf("CP\n"); + if (!PolygonMode) + Outputf("FI\n"); +} + + +/* + * 'RR_fill_rect_relative()' - Fill a rectangle relative to the current + * pen position. + */ + +void +RR_fill_rect_relative(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y; /* Transformed coordinates */ + + + if (num_params < 2) + return; + + x = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + PenPosition[0]; + y = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + PenPosition[1]; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + Outputf("%.3f %.3f LI\n", PenPosition[0], y); + Outputf("%.3f %.3f LI\n", x, y); + Outputf("%.3f %.3f LI\n", x, PenPosition[1]); + + Outputf("CP\n"); + if (!PolygonMode) + Outputf("FI\n"); +} + + +/* + * 'WG_fill_wedge()' - Fill a pie wedge. + */ + +void +WG_fill_wedge(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y; /* Transformed coordinates */ + float start, end, /* Start and end angles */ + theta, /* Current angle */ + dt, /* Step between points */ + radius; /* Radius of arc */ + + + if (num_params < 3) + return; + + radius = params[0].value.number; + start = params[1].value.number; + end = start + params[2].value.number; + + if (num_params > 3) + dt = (float)fabs(params[3].value.number); + else + dt = 5.0; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + + if (start < end) + for (theta = start + dt; theta < end; theta += dt) + { + x = (float)(PenPosition[0] + + radius * cos(M_PI * theta / 180.0) * Transform[0][0] + + radius * sin(M_PI * theta / 180.0) * Transform[0][1]); + y = (float)(PenPosition[1] + + radius * cos(M_PI * theta / 180.0) * Transform[1][0] + + radius * sin(M_PI * theta / 180.0) * Transform[1][1]); + + Outputf("%.3f %.3f LI\n", x, y); + } + else + for (theta = start - dt; theta > end; theta -= dt) + { + x = (float)(PenPosition[0] + + radius * cos(M_PI * theta / 180.0) * Transform[0][0] + + radius * sin(M_PI * theta / 180.0) * Transform[0][1]); + y = (float)(PenPosition[1] + + radius * cos(M_PI * theta / 180.0) * Transform[1][0] + + radius * sin(M_PI * theta / 180.0) * Transform[1][1]); + + Outputf("%.3f %.3f LI\n", x, y); + } + + x = (float)(PenPosition[0] + + radius * cos(M_PI * end / 180.0) * Transform[0][0] + + radius * sin(M_PI * end / 180.0) * Transform[0][1]); + y = (float)(PenPosition[1] + + radius * cos(M_PI * end / 180.0) * Transform[1][0] + + radius * sin(M_PI * end / 180.0) * Transform[1][1]); + Outputf("%.3f %.3f LI\n", x, y); + + Outputf("CP\n"); + if (!PolygonMode) + Outputf("FI\n"); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-prolog.c b/filter/hpgl-prolog.c new file mode 100644 index 0000000000..0d8aac7045 --- /dev/null +++ b/filter/hpgl-prolog.c @@ -0,0 +1,192 @@ +/* + * "$Id$" + * + * HP-GL/2 prolog routines for for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * OutputProlog() - Output the PostScript prolog... + * OutputTrailer() - Output the PostScript trailer... + * Outputf() - Write a formatted string to the output file, creating the + * page header as needed... + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" +#include + + +/* + * 'OutputProlog()' - Output the PostScript prolog... + */ + +void +OutputProlog(char *title, /* I - Job title */ + char *user, /* I - Username */ + int shading, /* I - Type of shading */ + float penwidth) /* I - Default pen width */ +{ + FILE *prolog; /* Prolog file */ + char line[255]; /* Line from prolog file */ + time_t curtime; /* Current time */ + struct tm *curtm; /* Current date */ + + + curtime = time(NULL); + curtm = localtime(&curtime); + + puts("%!PS-Adobe-3.0"); + printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", + PageLeft, PageBottom, PageRight, PageTop); + puts("%%Pages: (atend)"); + printf("%%%%LanguageLevel: %d\n", LanguageLevel); + puts("%%DocumentData: Clean7Bit"); + puts("%%DocumentSuppliedResources: procset hpgltops 1.0 0"); + puts("%%DocumentNeededResources: font Courier Helvetica"); + puts("%%Creator: hpgltops/" CUPS_SVERSION); + strftime(line, sizeof(line), "%%%%CreationDate: %c", curtm); + puts(line); + printf("%%%%Title: %s\n", title); + printf("%%%%For: %s\n", user); + if (Orientation & 1) + puts("%%Orientation: Landscape"); + puts("%%EndComments"); + puts("%%BeginProlog"); + printf("/DefaultPenWidth %.2f def\n", penwidth * 72.0 / 25.4); + puts("3.0 setmiterlimit"); + if (!shading) /* Black only */ + puts("/setrgbcolor { pop pop pop } bind def"); + else if (!ColorDevice) /* Greyscale */ + puts("/setrgbcolor { 0.08 mul exch 0.61 mul add exch 0.31 mul add setgray } bind def\n"); + + if ((prolog = fopen(CUPS_DATADIR "/data/HPGLprolog", "r")) == NULL) + { + perror("ERROR: Unable to open HPGL prolog \"" CUPS_DATADIR "/data/HPGLprolog\" for reading"); + exit(1); + } + + while (fgets(line, sizeof(line), prolog) != NULL) + fputs(line, stdout); + + fclose(prolog); + + puts("%%EndProlog"); + + IN_initialize(0, NULL); +} + + +/* + * 'OutputTrailer()' - Output the PostScript trailer... + */ + +void +OutputTrailer(void) +{ + if (PageDirty) + PG_advance_page(0, NULL); + + puts("%%BeginTrailer"); + printf("%%%%Pages: %d\n", PageCount); + puts("%%EOF"); +} + + +/* + * 'Outputf()' - Write a formatted string to the output file, creating the + * page header as needed... + */ + +int /* O - Number of bytes written */ +Outputf(const char *format, /* I - Printf-style string */ + ...) /* I - Additional args as needed */ +{ + va_list ap; /* Argument pointer */ + int bytes; /* Number of bytes written */ + + + /* + * Write the page header as needed... + */ + + if (!PageDirty) + { + PageDirty = 1; + PageCount ++; + + printf("%%%%Page: %d %d\n", PageCount, PageCount); + printf("/PenScaling %.3f def\n", PenScaling); + puts("gsave"); + + if (Duplex && (PageCount & 1) == 0) + switch ((PageRotation / 90) & 3) + { + case 0 : + printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom); + break; + case 1 : + printf("%.1f %.1f translate\n", PageLength - PageTop, + PageWidth - PageRight); + break; + case 2 : + printf("%.1f %.1f translate\n", PageLeft, PageLength - PageTop); + break; + case 3 : + printf("%.1f %.1f translate\n", PageBottom, PageLeft); + break; + } + else + switch ((PageRotation / 90) & 3) + { + case 0 : + printf("%.1f %.1f translate\n", PageLeft, PageBottom); + break; + case 1 : + printf("%.1f %.1f translate\n", PageBottom, PageWidth - PageRight); + break; + case 2 : + printf("%.1f %.1f translate\n", PageWidth - PageRight, + PageLength - PageTop); + break; + case 3 : + printf("%.1f %.1f translate\n", PageLength - PageTop, PageLeft); + break; + } + } + + /* + * Write the string to the output file... + */ + + va_start(ap, format); + bytes = vprintf(format, ap); + va_end(ap); + + return (bytes); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-vector.c b/filter/hpgl-vector.c new file mode 100644 index 0000000000..d900307b2a --- /dev/null +++ b/filter/hpgl-vector.c @@ -0,0 +1,704 @@ +/* + * "$Id$" + * + * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * AA_arc_absolute() - Draw an arc. + * AR_arc_relative() - Draw an arc relative to the current pen + * AT_arc_absolute3() - Draw an arc using 3 points. + * CI_circle() - Draw a circle. + * PA_plot_absolute() - Plot a line using absolute coordinates. + * PD_pen_down() - Start drawing. + * PE_polygon_encoded() - Draw an encoded polyline. + * PR_plot_relative() - Plot a line using relative coordinates. + * PU_pen_up() - Stop drawing. + * RT_arc_relative3() - Draw an arc through 3 points relative to the + * decode_number() - Decode an encoded number. + * plot_points() - Plot the specified points. + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" + + +/* + * Local functions... + */ + +static double decode_number(unsigned char **, int, double); +static void plot_points(int, param_t *); + + +/* + * 'AA_arc_absolute()' - Draw an arc. + */ + +void +AA_arc_absolute(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y, /* Transformed coordinates */ + dx, dy; /* Distance from current pen */ + float start, end, /* Start and end angles */ + theta, /* Current angle */ + dt, /* Step between points */ + radius; /* Radius of arc */ + + + if (num_params < 3) + return; + + x = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + Transform[0][2]; + y = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + Transform[1][2]; + + dx = PenPosition[0] - x; + dy = PenPosition[1] - y; + + start = (float)(180.0 * atan2(dy, dx) / M_PI); + if (start < 0.0) + start += 360.0f; + + end = start + params[2].value.number; + radius = (float)hypot(dx, dy); + + if (PenDown) + { + if (num_params > 3 && params[3].value.number > 0.0) + dt = (float)fabs(params[3].value.number); + else + dt = 5.0; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + + if (start < end) + for (theta = start + dt; theta < end; theta += dt) + { + PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); + PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); + + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + } + else + for (theta = start - dt; theta > end; theta -= dt) + { + PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); + PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); + + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + } + } + + PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0)); + PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0)); + + if (PenDown) + { + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + + if (!PolygonMode) + Outputf("ST\n"); + } +} + + +/* + * 'AR_arc_relative()' - Draw an arc relative to the current pen + * position. + */ + +void +AR_arc_relative(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y, /* Transformed coordinates */ + dx, dy; /* Distance from current pen */ + float start, end, /* Start and end angles */ + theta, /* Current angle */ + dt, /* Step between points */ + radius; /* Radius of arc */ + + + if (num_params < 3) + return; + + x = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + PenPosition[0]; + y = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + PenPosition[1]; + + dx = PenPosition[0] - x; + dy = PenPosition[1] - y; + + start = (float)(180.0 * atan2(dy, dx) / M_PI); + if (start < 0.0) + start += 360.0f; + + end = start + params[2].value.number; + radius = (float)hypot(dx, dy); + + if (PenDown) + { + if (num_params > 3 && params[3].value.number > 0.0) + dt = (float)fabs(params[3].value.number); + else + dt = 5.0; + + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + + if (start < end) + for (theta = start + dt; theta < end; theta += dt) + { + PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); + PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); + + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + } + else + for (theta = start - dt; theta > end; theta -= dt) + { + PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0)); + PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0)); + + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + } + } + + PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0)); + PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0)); + + if (PenDown) + { + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + + if (!PolygonMode) + Outputf("ST\n"); + } +} + + +/* + * 'AT_arc_absolute3()' - Draw an arc using 3 points. + * + * Note: + * + * Currently this only draws two line segments through the + * specified points. + */ + +void +AT_arc_absolute3(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params < 4) + return; + + if (PenDown) + { + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + + PenPosition[0] = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + Transform[0][2]; + PenPosition[1] = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + Transform[1][2]; + + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + } + + PenPosition[0] = Transform[0][0] * params[2].value.number + + Transform[0][1] * params[3].value.number + + Transform[0][2]; + PenPosition[1] = Transform[1][0] * params[2].value.number + + Transform[1][1] * params[3].value.number + + Transform[1][2]; + + if (PenDown) + { + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + + if (!PolygonMode) + Outputf("ST\n"); + } +} + + +/* + * 'CI_circle()' - Draw a circle. + */ + +void +CI_circle(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + float x, y; /* Transformed coordinates */ + float theta, /* Current angle */ + dt, /* Step between points */ + radius; /* Radius of circle */ + + + if (num_params < 1) + return; + + if (!PenDown) + return; + + radius = params[0].value.number; + + if (num_params > 1) + dt = (float)fabs(params[1].value.number); + else + dt = 5.0; + + if (!PolygonMode) + Outputf("MP\n"); + + for (theta = 0.0; theta < 360.0; theta += dt) + { + x = (float)(PenPosition[0] + + radius * cos(M_PI * theta / 180.0) * Transform[0][0] + + radius * sin(M_PI * theta / 180.0) * Transform[0][1]); + y = (float)(PenPosition[1] + + radius * cos(M_PI * theta / 180.0) * Transform[1][0] + + radius * sin(M_PI * theta / 180.0) * Transform[1][1]); + + Outputf("%.3f %.3f %s\n", x, y, theta == 0.0 ? "MO" : "LI"); + } + + Outputf("CP\n"); + if (!PolygonMode) + Outputf("ST\n"); +} + + +/* + * 'PA_plot_absolute()' - Plot a line using absolute coordinates. + */ + +void +PA_plot_absolute(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + PenMotion = 0; + + if (num_params > 1) + plot_points(num_params, params); +} + + +/* + * 'PD_pen_down()' - Start drawing. + */ + +void +PD_pen_down(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + PenDown = 1; + + if (num_params > 1) + plot_points(num_params, params); +} + + +/* + * 'PE_polygon_encoded()' - Draw an encoded polyline. + */ + +void +PE_polyline_encoded(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + unsigned char *s; /* Pointer into string */ + int temp, /* Temporary value */ + base_bits, /* Data bits per byte */ + draw, /* Draw or move */ + abscoords; /* Use absolute coordinates */ + double tx, ty, /* Transformed coordinates */ + x, y, /* Raw coordinates */ + frac_bits; /* Multiplier for encoded number */ + + + base_bits = 6; + frac_bits = 1.0; + draw = 1; + abscoords = 0; + + if (num_params == 0) + return; + + if (!PolygonMode) + { + Outputf("MP\n"); + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + } + + for (s = (unsigned char *)params[0].value.string; *s != '\0';) + switch (*s) + { + case '7' : + s ++; + base_bits = 5; + break; + case ':' : /* Select pen */ + s ++; + temp = (int)decode_number(&s, base_bits, 1.0); + Outputf("P%d W%d\n", temp, temp); + break; + case '<' : /* Next coords are a move-to */ + draw = 0; + s ++; + break; + case '>' : /* Set fractional bits */ + s ++; + temp = (int)decode_number(&s, base_bits, 1.0); + frac_bits = 1.0 / (1 << temp); + break; + case '=' : /* Next coords are absolute */ + s ++; + abscoords = 1; + break; + default : + if (*s >= 63) + { + /* + * Coordinate... + */ + + x = decode_number(&s, base_bits, frac_bits); + y = decode_number(&s, base_bits, frac_bits); + + if (abscoords) + { + tx = Transform[0][0] * x + Transform[0][1] * y + + Transform[0][2]; + ty = Transform[1][0] * x + Transform[1][1] * y + + Transform[1][2]; + } + else if (x == 0.0 && y == 0.0) + { + draw = 1; + continue; + } + else + { + tx = Transform[0][0] * x + Transform[0][1] * y + + PenPosition[0]; + ty = Transform[1][0] * x + Transform[1][1] * y + + PenPosition[1]; + } + + if (draw) + Outputf("%.3f %.3f LI\n", tx, ty); + else + Outputf("%.3f %.3f MO\n", tx, ty); + + PenPosition[0] = (float)tx; + PenPosition[1] = (float)ty; + + draw = 1; + abscoords = 0; + } + else + { + /* + * Junk - ignore... + */ + + if (*s != '\n' && *s != '\r') + fprintf(stderr, "WARNING: ignoring illegal PE char \'%c\'...\n", *s); + s ++; + } + break; + } + + if (!PolygonMode) + Outputf("ST\n"); +} + + +/* + * 'PR_plot_relative()' - Plot a line using relative coordinates. + */ + +void +PR_plot_relative(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + PenMotion = 1; + + if (num_params > 1) + plot_points(num_params, params); +} + + +/* + * 'PU_pen_up()' - Stop drawing. + */ + +void +PU_pen_up(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + PenDown = 0; + + if (num_params > 1) + plot_points(num_params, params); +} + + +/* + * 'RT_arc_relative3()' - Draw an arc through 3 points relative to the + * current pen position. + * + * Note: + * + * This currently only draws two line segments through the specified + * points. + */ + +void +RT_arc_relative3(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params < 4) + return; + + if (PenDown) + { + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + + PenPosition[0] = Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + PenPosition[0]; + PenPosition[1] = Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + PenPosition[1]; + + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + } + + PenPosition[0] = Transform[0][0] * params[2].value.number + + Transform[0][1] * params[3].value.number + + PenPosition[0]; + PenPosition[1] = Transform[1][0] * params[2].value.number + + Transform[1][1] * params[3].value.number + + PenPosition[1]; + + if (PenDown) + { + Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]); + + if (!PolygonMode) + Outputf("ST\n"); + } +} + + +/* + * 'decode_number()' - Decode an encoded number. + */ + +static double /* O - Value */ +decode_number(unsigned char **s, /* IO - String to decode */ + int base_bits, /* I - Number of data bits per byte */ + double frac_bits) /* I - Multiplier for fractional data */ +{ + double temp, /* Current value */ + shift; /* Multiplier */ + int sign; /* Sign of result */ + + + sign = 0; + + if (base_bits == 5) + { + for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++) + if (**s >= 95 && **s < 127) + { + if (sign == 0) + { + if ((**s - 95) & 1) + sign = -1; + else + sign = 1; + + temp += ((**s - 95) & ~1) * shift; + } + else + temp += (**s - 95) * shift; + break; + } + else if (**s < 63) + { + if (**s != '\r' && **s != '\n') + fprintf(stderr, "hpgl2ps: Bad PE character \'%c\'!\n", **s); + + continue; + } + else + { + if (sign == 0) + { + if ((**s - 63) & 1) + sign = -1; + else + sign = 1; + + temp += ((**s - 63) & ~1) * shift; + } + else + temp += (**s - 63) * shift; + + shift *= 32.0; + } + } + else + { + for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++) + if (**s >= 191 && **s < 255) + { + if (sign == 0) + { + if ((**s - 191) & 1) + sign = -1; + else + sign = 1; + + temp += ((**s - 191) & ~1) * shift; + } + else + temp += (**s - 191) * shift; + break; + } + else if (**s < 63) + { + if (**s != '\r' && **s != '\n') + fprintf(stderr, "hpgl2ps: Bad PE character \'%c\'!\n", **s); + + continue; + } + else + { + if (sign == 0) + { + if ((**s - 63) & 1) + sign = -1; + else + sign = 1; + + temp += ((**s - 63) & ~1) * shift; + } + else + temp += (**s - 63) * shift; + + shift *= 64.0; + } + } + + (*s) ++; + + return (temp * sign); +} + + +/* + * 'plot_points()' - Plot the specified points. + */ + +static void +plot_points(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + int i; /* Looping var */ + float x, y; /* Transformed coordinates */ + + + if (PenDown) + { + if (!PolygonMode) + Outputf("MP\n"); + + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + } + + for (i = 0; i < num_params; i += 2) + { + if (PenMotion == 0) + { + x = Transform[0][0] * params[i + 0].value.number + + Transform[0][1] * params[i + 1].value.number + + Transform[0][2]; + y = Transform[1][0] * params[i + 0].value.number + + Transform[1][1] * params[i + 1].value.number + + Transform[1][2]; + } + else + { + x = Transform[0][0] * params[i + 0].value.number + + Transform[0][1] * params[i + 1].value.number + + PenPosition[0]; + y = Transform[1][0] * params[i + 0].value.number + + Transform[1][1] * params[i + 1].value.number + + PenPosition[1]; + } + + if (PenDown) + Outputf("%.3f %.3f LI\n", x, y); + + PenPosition[0] = x; + PenPosition[1] = y; + } + + if (PenDown) + { + if (!PolygonMode) + Outputf("ST\n"); + } +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgltops.h b/filter/hpgltops.h new file mode 100644 index 0000000000..4cd32e0f0a --- /dev/null +++ b/filter/hpgltops.h @@ -0,0 +1,196 @@ +/* + * "$Id$" + * + * HP-GL/2 to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Include necessary headers... + */ + +#include "common.h" +#include + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif /* M_PI */ + +/* + * Parameter value structure... + */ + +typedef struct +{ + int type; + union + { + float number; + char *string; + } value; +} param_t; + +#define PARAM_ABSOLUTE 0 +#define PARAM_RELATIVE 1 +#define PARAM_STRING 2 + + +/* + * Globals... + */ + +#ifdef _HPGL_MAIN_C_ +# define VAR +# define VALUE(x) =x +# define VALUE2(x,y) ={x,y} +#else +# define VAR extern +# define VALUE(x) +# define VALUE2(x,y) +#endif /* _HPGL_MAIN_C_ */ + +VAR float P1[2], /* Lower-lefthand physical limit */ + P2[2], /* Upper-righthand physical limit */ + IW1[2], /* Window lower-lefthand limit */ + IW2[2]; /* Window upper-righthand limit */ +VAR int Rotation VALUE(0); /* Page rotation */ +VAR int ScalingType VALUE(-1); /* Type of scaling (-1 for none) */ +VAR float Scaling1[2], /* Lower-lefthand user limit */ + Scaling2[2]; /* Upper-righthand user limit */ +VAR float Transform[2][3]; /* Transform matrix */ +VAR int PageRotation VALUE(0); /* Page/plot rotation */ + +VAR char StringTerminator VALUE('\003'); /* Terminator for labels */ +VAR float PenPosition[2] VALUE2(0.0f, 0.0f), + /* Current pen position */ + PenScaling VALUE(1.0f); /* Pen width scaling factor */ +VAR int PenMotion VALUE(0), /* 0 = absolute, 1 = relative */ + PenNumber VALUE(1), /* Current pen number */ + PenCount VALUE(8), /* Number of pens */ + PenDown VALUE(0), /* 0 = pen up, 1 = pen down */ + PolygonMode VALUE(0), /* Drawing polygons? */ + PageCount VALUE(1), /* Number of pages in plot */ + PageDirty VALUE(0), /* Current page written on? */ + WidthUnits VALUE(0); /* 0 = mm, 1 = proportionate */ +VAR float PlotSize[2] VALUE2(2592.0f, 3456.0f); + /* Plot size */ +VAR int CharFillMode VALUE(0), /* Where to draw labels */ + CharPen VALUE(0), /* Pen to use for labels */ + CharFont VALUE(0); /* Font to use for labels */ +VAR float CharHeight[2] VALUE2(11.5f,11.5f); + /* Size of font for labels */ +VAR int FitPlot VALUE(0); /* 1 = fit to page */ +VAR float ColorRange[3][2] /* Range of color values */ +#ifdef _HPGL_MAIN_C_ + = { + { 0.0, 255.0 }, + { 0.0, 255.0 }, + { 0.0, 255.0 } + } +#endif /* _HPGL_MAIN_C_ */ +; + +/* + * Prototypes... + */ + +/* hpgl-input.c */ +extern int ParseCommand(FILE *fp, char *name, param_t **params); +extern void FreeParameters(int num_params, param_t *params); + +/* hpgl-config.c */ +extern void update_transform(void); +extern void BP_begin_plot(int num_params, param_t *params); +extern void DF_default_values(int num_params, param_t *params); +extern void IN_initialize(int num_params, param_t *params); +extern void IP_input_absolute(int num_params, param_t *params); +extern void IR_input_relative(int num_params, param_t *params); +extern void IW_input_window(int num_params, param_t *params); +extern void PG_advance_page(int num_params, param_t *params); +extern void PS_plot_size(int num_params, param_t *params); +extern void RO_rotate(int num_params, param_t *params); +extern void RP_replot(int num_params, param_t *params); +extern void SC_scale(int num_params, param_t *params); + +/* hpgl-vector.c */ +extern void AA_arc_absolute(int num_params, param_t *params); +extern void AR_arc_relative(int num_params, param_t *params); +extern void AT_arc_absolute3(int num_params, param_t *params); +extern void CI_circle(int num_params, param_t *params); +extern void PA_plot_absolute(int num_params, param_t *params); +extern void PD_pen_down(int num_params, param_t *params); +extern void PE_polyline_encoded(int num_params, param_t *params); +extern void PR_plot_relative(int num_params, param_t *params); +extern void PU_pen_up(int num_params, param_t *params); +extern void RT_arc_relative3(int num_params, param_t *params); + +/* hpgl-polygon.c */ +extern void EA_edge_rect_absolute(int num_params, param_t *params); +extern void EP_edge_polygon(int num_params, param_t *params); +extern void ER_edge_rect_relative(int num_params, param_t *params); +extern void EW_edge_wedge(int num_params, param_t *params); +extern void FP_fill_polygon(int num_params, param_t *params); +extern void PM_polygon_mode(int num_params, param_t *params); +extern void RA_fill_rect_absolute(int num_params, param_t *params); +extern void RR_fill_rect_relative(int num_params, param_t *params); +extern void WG_fill_wedge(int num_params, param_t *params); + +/* hpgl-char.c */ +extern void AD_define_alternate(int num_params, param_t *params); +extern void CF_character_fill(int num_params, param_t *params); +extern void CP_character_plot(int num_params, param_t *params); +extern void DI_absolute_direction(int num_params, param_t *params); +extern void DR_relative_direction(int num_params, param_t *params); +extern void DT_define_label_term(int num_params, param_t *params); +extern void DV_define_variable_path(int num_params, param_t *params); +extern void ES_extra_space(int num_params, param_t *params); +extern void LB_label(int num_params, param_t *params); +extern void LO_label_origin(int num_params, param_t *params); +extern void SA_select_alternate(int num_params, param_t *params); +extern void SD_define_standard(int num_params, param_t *params); +extern void SI_absolute_size(int num_params, param_t *params); +extern void SL_character_slant(int num_params, param_t *params); +extern void SR_relative_size(int num_params, param_t *params); +extern void SS_select_standard(int num_params, param_t *params); +extern void TD_transparent_data(int num_params, param_t *params); + +/* hpgl-attr.c */ +extern void AC_anchor_corner(int num_params, param_t *params); +extern void CR_color_range(int num_params, param_t *params); +extern void FT_fill_type(int num_params, param_t *params); +extern void LA_line_attributes(int num_params, param_t *params); +extern void LT_line_type(int num_params, param_t *params); +extern void NP_number_pens(int num_params, param_t *params); +extern void PC_pen_color(int num_params, param_t *params); +extern void PW_pen_width(int num_params, param_t *params); +extern void RF_raster_fill(int num_params, param_t *params); +extern void SM_symbol_mode(int num_params, param_t *params); +extern void SP_select_pen(int num_params, param_t *params); +extern void UL_user_line_type(int num_params, param_t *params); +extern void WU_width_units(int num_params, param_t *params); + +/* hpgl-prolog.c */ +extern void OutputProlog(char *title, char *user, int shading, float penwidth); +extern void OutputTrailer(void); +extern int Outputf(const char *format, ...); + +/* + * End of "$Id$". + */ diff --git a/filter/image-colorspace.c b/filter/image-colorspace.c new file mode 100644 index 0000000000..12f40cd84e --- /dev/null +++ b/filter/image-colorspace.c @@ -0,0 +1,910 @@ +/* + * "$Id$" + * + * Colorspace conversions for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageWhiteToWhite() - Convert luminance colors to device-dependent + * ImageWhiteToRGB() - Convert luminance data to RGB. + * ImageWhiteToBlack() - Convert luminance colors to black. + * ImageWhiteToCMY() - Convert luminance colors to CMY. + * ImageWhiteToCMYK() - Convert luminance colors to CMYK. + * ImageRGBToBlack() - Convert RGB data to black. + * ImageRGBToCMY() - Convert RGB colors to CMY. + * ImageRGBToCMYK() - Convert RGB colors to CMYK. + * ImageRGBToWhite() - Convert RGB colors to luminance. + * ImageRGBToRGB() - Convert RGB colors to device-dependent RGB. + * ImageLut() - Adjust all pixel values with the given LUT. + * ImageRGBAdjust() - Adjust the hue and saturation of the given RGB + * colors. + * huerotate() - Rotate the hue, maintaining luminance. + * ident() - Make an identity matrix. + * mult() - Multiply two matrices. + * saturate() - Make a saturation matrix. + * xform() - Transform a 3D point using a matrix... + * xrotate() - Rotate about the x (red) axis... + * yrotate() - Rotate about the y (green) axis... + * zrotate() - Rotate about the z (blue) axis... + * zshear() - Shear z using x and y... + */ + +/* + * Include necessary headers... + */ + +#include "image.h" +#include + + +/* + * Globals... + */ + +extern int ImageHaveProfile; +extern int ImageDensity[256]; +extern int ImageMatrix[3][3][256]; + +/* + * Local functions... + */ + +static void huerotate(float [3][3], float); +static void ident(float [3][3]); +static void mult(float [3][3], float [3][3], float [3][3]); +static void saturate(float [3][3], float); +static void xform(float [3][3], float, float, float, float *, float *, float *); +static void xrotate(float [3][3], float, float); +static void yrotate(float [3][3], float, float); +static void zrotate(float [3][3], float, float); +static void zshear(float [3][3], float, float); + + +/* + * 'ImageWhiteToWhite()' - Convert luminance colors to device-dependent + * luminance. + */ + +void +ImageWhiteToWhite(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (ImageHaveProfile) + while (count > 0) + { + *out++ = 255 - ImageDensity[255 - *in++]; + count --; + } + else if (in != out) + memcpy(out, in, count); +} + + +/* + * 'ImageWhiteToRGB()' - Convert luminance data to RGB. + */ + +void +ImageWhiteToRGB(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (ImageHaveProfile) + while (count > 0) + { + out[0] = 255 - ImageDensity[255 - *in++]; + out[1] = out[0]; + out[2] = out[0]; + out += 3; + count --; + } + else + while (count > 0) + { + *out++ = *in; + *out++ = *in; + *out++ = *in++; + count --; + } +} + + +/* + * 'ImageWhiteToBlack()' - Convert luminance colors to black. + */ + +void +ImageWhiteToBlack(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (ImageHaveProfile) + while (count > 0) + { + *out++ = ImageDensity[255 - *in++]; + count --; + } + else + while (count > 0) + { + *out++ = 255 - *in++; + count --; + } +} + + +/* + * 'ImageWhiteToCMY()' - Convert luminance colors to CMY. + */ + +void +ImageWhiteToCMY(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (ImageHaveProfile) + while (count > 0) + { + out[0] = ImageDensity[255 - *in++]; + out[1] = out[0]; + out[2] = out[0]; + out += 3; + count --; + } + else + while (count > 0) + { + *out++ = 255 - *in; + *out++ = 255 - *in; + *out++ = 255 - *in++; + count --; + } +} + + +/* + * 'ImageWhiteToCMYK()' - Convert luminance colors to CMYK. + */ + +void +ImageWhiteToCMYK(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (ImageHaveProfile) + while (count > 0) + { + *out++ = 0; + *out++ = 0; + *out++ = 0; + *out++ = ImageDensity[255 - *in++]; + count --; + } + else + while (count > 0) + { + *out++ = 0; + *out++ = 0; + *out++ = 0; + *out++ = 255 - *in++; + count --; + } +} + + +/* + * 'ImageRGBToBlack()' - Convert RGB data to black. + */ + +void +ImageRGBToBlack(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (ImageHaveProfile) + while (count > 0) + { + *out++ = ImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100]; + in += 3; + count --; + } + else + while (count > 0) + { + *out++ = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100; + in += 3; + count --; + } +} + + +/* + * 'ImageRGBToCMY()' - Convert RGB colors to CMY. + */ + +void +ImageRGBToCMY(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + int c, m, y, k; /* CMYK values */ + int cc, cm, cy; /* Calibrated CMY values */ + + + if (ImageHaveProfile) + while (count > 0) + { + c = 255 - *in++; + m = 255 - *in++; + y = 255 - *in++; + k = min(c, min(m, y)); + c -= k; + m -= k; + y -= k; + + cc = ImageMatrix[0][0][c] + + ImageMatrix[0][1][m] + + ImageMatrix[0][2][y] + k; + cm = ImageMatrix[1][0][c] + + ImageMatrix[1][1][m] + + ImageMatrix[1][2][y] + k; + cy = ImageMatrix[2][0][c] + + ImageMatrix[2][1][m] + + ImageMatrix[2][2][y] + k; + + if (cc < 0) + *out++ = 0; + else if (cc > 255) + *out++ = ImageDensity[255]; + else + *out++ = ImageDensity[cc]; + + if (cm < 0) + *out++ = 0; + else if (cm > 255) + *out++ = ImageDensity[255]; + else + *out++ = ImageDensity[cm]; + + if (cy < 0) + *out++ = 0; + else if (cy > 255) + *out++ = ImageDensity[255]; + else + *out++ = ImageDensity[cy]; + + count --; + } + else + while (count > 0) + { + c = 255 - in[0]; + m = 255 - in[1]; + y = 255 - in[2]; + k = min(c, min(m, y)); + + *out++ = (255 - in[1] / 4) * (c - k) / 255 + k; + *out++ = (255 - in[2] / 4) * (m - k) / 255 + k; + *out++ = (255 - in[0] / 4) * (y - k) / 255 + k; + in += 3; + count --; + } +} + + +/* + * 'ImageRGBToCMYK()' - Convert RGB colors to CMYK. + */ + +void +ImageRGBToCMYK(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count)/* I - Number of pixels */ +{ + int c, m, y, k, /* CMYK values */ + diff, /* Color differences */ + divk; /* Color divisor */ + int cc, cm, cy; /* Calibrated CMY values */ + + + if (ImageHaveProfile) + while (count > 0) + { + c = 255 - *in++; + m = 255 - *in++; + y = 255 - *in++; + k = min(c, min(m, y)); + + diff = 255 - (max(c, max(m, y)) - k); + k = k * diff / 255; + + if (k == 255) + c = m = y = 0; + else if (k > 0) + { + divk = 255 - k; + c = 255 * (c - k) / divk; + m = 255 * (m - k) / divk; + y = 255 * (y - k) / divk; + + if (c > 255) + c = 255; + + if (m > 255) + m = 255; + + if (y > 255) + y = 255; + } + + cc = (ImageMatrix[0][0][c] + + ImageMatrix[0][1][m] + + ImageMatrix[0][2][y]); + cm = (ImageMatrix[1][0][c] + + ImageMatrix[1][1][m] + + ImageMatrix[1][2][y]); + cy = (ImageMatrix[2][0][c] + + ImageMatrix[2][1][m] + + ImageMatrix[2][2][y]); + + if (cc < 0) + *out++ = 0; + else if (cc > 255) + *out++ = ImageDensity[255]; + else + *out++ = ImageDensity[cc]; + + if (cm < 0) + *out++ = 0; + else if (cm > 255) + *out++ = ImageDensity[255]; + else + *out++ = ImageDensity[cm]; + + if (cy < 0) + *out++ = 0; + else if (cy > 255) + *out++ = ImageDensity[255]; + else + *out++ = ImageDensity[cy]; + + *out++ = ImageDensity[k]; + + count --; + } + else + while (count > 0) + { + c = 255 - *in++; + m = 255 - *in++; + y = 255 - *in++; + k = min(c, min(m, y)); + + if (k == 255) + c = m = y = 0; + else if (k > 0) + { + divk = 255 - k; + c = 255 * (c - k) / divk; + m = 255 * (m - k) / divk; + y = 255 * (y - k) / divk; + + if (c > 255) + c = 255; + + if (m > 255) + m = 255; + + if (y > 255) + y = 255; + } + + *out++ = c; + *out++ = m; + *out++ = y; + *out++ = k; + + count --; + } +} + + +/* + * 'ImageRGBToWhite()' - Convert RGB colors to luminance. + */ + +void +ImageRGBToWhite(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (ImageHaveProfile) + while (count > 0) + { + *out++ = 255 - ImageDensity[255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100]; + in += 3; + count --; + } + else + while (count > 0) + { + *out++ = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100; + in += 3; + count --; + } +} + + +/* + * 'ImageRGBToRGB()' - Convert RGB colors to device-dependent RGB. + */ + +void +ImageRGBToRGB(const ib_t *in, /* I - Input pixels */ + ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + int c, m, y, k; /* CMYK values */ + int cr, cg, cb; /* Calibrated RGB values */ + + + if (ImageHaveProfile) + while (count > 0) + { + c = 255 - *in++; + m = 255 - *in++; + y = 255 - *in++; + k = min(c, min(m, y)); + c -= k; + m -= k; + y -= k; + + cr = ImageMatrix[0][0][c] + + ImageMatrix[0][1][m] + + ImageMatrix[0][2][y] + k; + cg = ImageMatrix[1][0][c] + + ImageMatrix[1][1][m] + + ImageMatrix[1][2][y] + k; + cb = ImageMatrix[2][0][c] + + ImageMatrix[2][1][m] + + ImageMatrix[2][2][y] + k; + + if (cr < 0) + *out++ = 255; + else if (cr > 255) + *out++ = 255 - ImageDensity[255]; + else + *out++ = 255 - ImageDensity[cr]; + + if (cg < 0) + *out++ = 255; + else if (cg > 255) + *out++ = 255 - ImageDensity[255]; + else + *out++ = 255 - ImageDensity[cg]; + + if (cb < 0) + *out++ = 255; + else if (cb > 255) + *out++ = 255 - ImageDensity[255]; + else + *out++ = 255 - ImageDensity[cb]; + + count --; + } + else if (in != out) + memcpy(out, in, count * 3); +} + + +/* + * 'ImageLut()' - Adjust all pixel values with the given LUT. + */ + +void +ImageLut(ib_t *pixels, /* IO - Input/output pixels */ + int count, /* I - Number of pixels/bytes to adjust */ + const ib_t *lut) /* I - Lookup table */ +{ + while (count > 0) + { + *pixels = lut[*pixels]; + pixels ++; + count --; + } +} + + +/* + * 'ImageRGBAdjust()' - Adjust the hue and saturation of the given RGB colors. + */ + +void +ImageRGBAdjust(ib_t *pixels, /* IO - Input/output pixels */ + int count, /* I - Number of pixels to adjust */ + int saturation, /* I - Color saturation (%) */ + int hue) /* I - Color hue (degrees) */ +{ + int i, j, k; /* Looping vars */ + float mat[3][3]; /* Color adjustment matrix */ + static int last_sat = 100, /* Last saturation used */ + last_hue = 0; /* Last hue used */ + static int lut[3][3][256]; /* Lookup table for matrix */ + + + if (saturation != last_sat || + hue != last_hue) + { + /* + * Build the color adjustment matrix... + */ + + ident(mat); + saturate(mat, saturation * 0.01); + huerotate(mat, (float)hue); + + /* + * Convert the matrix into a 3x3 array of lookup tables... + */ + + for (i = 0; i < 3; i ++) + for (j = 0; j < 3; j ++) + for (k = 0; k < 256; k ++) + lut[i][j][k] = mat[i][j] * k + 0.5; + + /* + * Save the saturation and hue to compare later... + */ + + last_sat = saturation; + last_hue = hue; + } + + /* + * Adjust each pixel in the given buffer. + */ + + while (count > 0) + { + i = lut[0][0][pixels[0]] + + lut[1][0][pixels[1]] + + lut[2][0][pixels[2]]; + if (i < 0) + pixels[0] = 0; + else if (i > 255) + pixels[0] = 255; + else + pixels[0] = i; + + i = lut[0][1][pixels[0]] + + lut[1][1][pixels[1]] + + lut[2][1][pixels[2]]; + if (i < 0) + pixels[1] = 0; + else if (i > 255) + pixels[1] = 255; + else + pixels[1] = i; + + i = lut[0][2][pixels[0]] + + lut[1][2][pixels[1]] + + lut[2][2][pixels[2]]; + if (i < 0) + pixels[2] = 0; + else if (i > 255) + pixels[2] = 255; + else + pixels[2] = i; + + count --; + pixels += 3; + } +} + + +/* + * The color saturation/hue matrix stuff is provided thanks to Mr. Paul + * Haeberli at "http://www.sgi.com/grafica/matrix/index.html". + */ + +/* + * 'huerotate()' - Rotate the hue, maintaining luminance. + */ + +static void +huerotate(float mat[3][3], /* I - Matrix to append to */ + float rot) /* I - Hue rotation in degrees */ +{ + float hmat[3][3]; /* Hue matrix */ + float lx, ly, lz; /* Luminance vector */ + float xrs, xrc; /* X rotation sine/cosine */ + float yrs, yrc; /* Y rotation sine/cosine */ + float zrs, zrc; /* Z rotation sine/cosine */ + float zsx, zsy; /* Z shear x/y */ + + + /* + * Load the identity matrix... + */ + + ident(hmat); + + /* + * Rotate the grey vector into positive Z... + */ + + xrs = M_SQRT1_2; + xrc = M_SQRT1_2; + xrotate(hmat,xrs,xrc); + + yrs = -1.0 / sqrt(3.0); + yrc = -M_SQRT2 * yrs; + yrotate(hmat,yrs,yrc); + + /* + * Shear the space to make the luminance plane horizontal... + */ + + xform(hmat, 0.3086, 0.6094, 0.0820, &lx, &ly, &lz); + zsx = lx / lz; + zsy = ly / lz; + zshear(hmat, zsx, zsy); + + /* + * Rotate the hue... + */ + + zrs = sin(rot * M_PI / 180.0); + zrc = cos(rot * M_PI / 180.0); + + zrotate(hmat, zrs, zrc); + + /* + * Unshear the space to put the luminance plane back... + */ + + zshear(hmat, -zsx, -zsy); + + /* + * Rotate the grey vector back into place... + */ + + yrotate(hmat, -yrs, yrc); + xrotate(hmat, -xrs, xrc); + + /* + * Append it to the current matrix... + */ + + mult(hmat, mat, mat); +} + + +/* + * 'ident()' - Make an identity matrix. + */ + +static void +ident(float mat[3][3]) /* I - Matrix to identify */ +{ + mat[0][0] = 1.0; + mat[0][1] = 0.0; + mat[0][2] = 0.0; + mat[1][0] = 0.0; + mat[1][1] = 1.0; + mat[1][2] = 0.0; + mat[2][0] = 0.0; + mat[2][1] = 0.0; + mat[2][2] = 1.0; +} + + +/* + * 'mult()' - Multiply two matrices. + */ + +static void +mult(float a[3][3], /* I - First matrix */ + float b[3][3], /* I - Second matrix */ + float c[3][3]) /* I - Destination matrix */ +{ + int x, y; /* Looping vars */ + float temp[3][3]; /* Temporary matrix */ + + + /* + * Multiply a and b, putting the result in temp... + */ + + for (y = 0; y < 3; y ++) + for (x = 0; x < 3; x ++) + temp[y][x] = b[y][0] * a[0][x] + + b[y][1] * a[1][x] + + b[y][2] * a[2][x]; + + /* + * Copy temp to c (that way c can be a pointer to a or b). + */ + + memcpy(c, temp, sizeof(temp)); +} + + +/* + * 'saturate()' - Make a saturation matrix. + */ + +static void +saturate(float mat[3][3], /* I - Matrix to append to */ + float sat) /* I - Desired color saturation */ +{ + float smat[3][3]; /* Saturation matrix */ + + + smat[0][0] = (1.0 - sat) * 0.3086 + sat; + smat[0][1] = (1.0 - sat) * 0.3086; + smat[0][2] = (1.0 - sat) * 0.3086; + smat[1][0] = (1.0 - sat) * 0.6094; + smat[1][1] = (1.0 - sat) * 0.6094 + sat; + smat[1][2] = (1.0 - sat) * 0.6094; + smat[2][0] = (1.0 - sat) * 0.0820; + smat[2][1] = (1.0 - sat) * 0.0820; + smat[2][2] = (1.0 - sat) * 0.0820 + sat; + + mult(smat, mat, mat); +} + + +/* + * 'xform()' - Transform a 3D point using a matrix... + */ + +static void +xform(float mat[3][3], /* I - Matrix */ + float x, /* I - Input X coordinate */ + float y, /* I - Input Y coordinate */ + float z, /* I - Input Z coordinate */ + float *tx, /* O - Output X coordinate */ + float *ty, /* O - Output Y coordinate */ + float *tz) /* O - Output Z coordinate */ +{ + *tx = x * mat[0][0] + y * mat[1][0] + z * mat[2][0]; + *ty = x * mat[0][1] + y * mat[1][1] + z * mat[2][1]; + *tz = x * mat[0][2] + y * mat[1][2] + z * mat[2][2]; +} + + +/* + * 'xrotate()' - Rotate about the x (red) axis... + */ + +static void +xrotate(float mat[3][3], /* I - Matrix */ + float rs, /* I - Rotation angle sine */ + float rc) /* I - Rotation angle cosine */ +{ + float rmat[3][3]; /* I - Rotation matrix */ + + + rmat[0][0] = 1.0; + rmat[0][1] = 0.0; + rmat[0][2] = 0.0; + + rmat[1][0] = 0.0; + rmat[1][1] = rc; + rmat[1][2] = rs; + + rmat[2][0] = 0.0; + rmat[2][1] = -rs; + rmat[2][2] = rc; + + mult(rmat, mat, mat); +} + + +/* + * 'yrotate()' - Rotate about the y (green) axis... + */ + +static void +yrotate(float mat[3][3], /* I - Matrix */ + float rs, /* I - Rotation angle sine */ + float rc) /* I - Rotation angle cosine */ +{ + float rmat[3][3]; /* I - Rotation matrix */ + + + rmat[0][0] = rc; + rmat[0][1] = 0.0; + rmat[0][2] = -rs; + + rmat[1][0] = 0.0; + rmat[1][1] = 1.0; + rmat[1][2] = 0.0; + + rmat[2][0] = rs; + rmat[2][1] = 0.0; + rmat[2][2] = rc; + + mult(rmat,mat,mat); +} + + +/* + * 'zrotate()' - Rotate about the z (blue) axis... + */ + +static void +zrotate(float mat[3][3], /* I - Matrix */ + float rs, /* I - Rotation angle sine */ + float rc) /* I - Rotation angle cosine */ +{ + float rmat[3][3]; /* I - Rotation matrix */ + + + rmat[0][0] = rc; + rmat[0][1] = rs; + rmat[0][2] = 0.0; + + rmat[1][0] = -rs; + rmat[1][1] = rc; + rmat[1][2] = 0.0; + + rmat[2][0] = 0.0; + rmat[2][1] = 0.0; + rmat[2][2] = 1.0; + + mult(rmat,mat,mat); +} + + +/* + * 'zshear()' - Shear z using x and y... + */ + +static void +zshear(float mat[3][3], /* I - Matrix */ + float dx, /* I - X shear */ + float dy) /* I - Y shear */ +{ + float smat[3][3]; /* Shear matrix */ + + + smat[0][0] = 1.0; + smat[0][1] = 0.0; + smat[0][2] = dx; + + smat[1][0] = 0.0; + smat[1][1] = 1.0; + smat[1][2] = dy; + + smat[2][0] = 0.0; + smat[2][1] = 0.0; + smat[2][2] = 1.0; + + mult(smat, mat, mat); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image-gif.c b/filter/image-gif.c new file mode 100644 index 0000000000..26f3185e28 --- /dev/null +++ b/filter/image-gif.c @@ -0,0 +1,644 @@ +/* + * "$Id$" + * + * GIF image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadGIF() - Read a GIF image file. + * gif_read_cmap() - Read the colormap from a GIF file... + * gif_get_block() - Read a GIF data block... + * gif_get_code() - Get a LZW code from the file... + * gif_read_lzw() - Read a byte from the LZW stream... + * gif_read_image() - Read a GIF image stream... + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + + +/* + * GIF definitions... + */ + +#define GIF_INTERLACE 0x40 +#define GIF_COLORMAP 0x80 + +typedef ib_t gif_cmap_t[256][4]; + + +/* + * Local globals... + */ + +static int gif_eof = 0; /* Did we hit EOF? */ + + +/* + * Local functions... + */ + +static int gif_read_cmap(FILE *fp, int ncolors, gif_cmap_t cmap, + int *gray); +static int gif_get_block(FILE *fp, unsigned char *buffer); +static int gif_get_code (FILE *fp, int code_size, int first_time); +static int gif_read_lzw(FILE *fp, int first_time, int input_code_size); +static int gif_read_image(FILE *fp, image_t *img, gif_cmap_t cmap, + int interlace); + + +/* + * 'ImageReadGIF()' - Read a GIF image file. + */ + +int /* O - Read status */ +ImageReadGIF(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + unsigned char buf[1024]; /* Input buffer */ + gif_cmap_t cmap; /* Colormap */ + int i, /* Looping var */ + bpp, /* Bytes per pixel */ + gray, /* Grayscale image? */ + ncolors, /* Bits per pixel */ + transparent; /* Transparent color index */ + + + /* + * Read the header; we already know it is a GIF file... + */ + + fread(buf, 13, 1, fp); + + img->xsize = (buf[7] << 8) | buf[6]; + img->ysize = (buf[9] << 8) | buf[8]; + ncolors = 2 << (buf[10] & 0x07); + gray = primary == IMAGE_BLACK || primary == IMAGE_WHITE; + + if (buf[10] & GIF_COLORMAP) + if (gif_read_cmap(fp, ncolors, cmap, &gray)) + { + fclose(fp); + return (-1); + } + + transparent = -1; + + for (;;) + { + switch (getc(fp)) + { + case ';' : /* End of image */ + fclose(fp); + return (-1); /* Early end of file */ + + case '!' : /* Extension record */ + buf[0] = getc(fp); + if (buf[0] == 0xf9) /* Graphic Control Extension */ + { + gif_get_block(fp, buf); + if (buf[0] & 1) /* Get transparent color index */ + transparent = buf[3]; + } + + while (gif_get_block(fp, buf) != 0); + break; + + case ',' : /* Image data */ + fread(buf, 9, 1, fp); + + if (buf[8] & GIF_COLORMAP) + { + ncolors = 2 << (buf[8] & 0x07); + gray = primary == IMAGE_BLACK || primary == IMAGE_WHITE; + + if (gif_read_cmap(fp, ncolors, cmap, &gray)) + { + fclose(fp); + return (-1); + } + } + + if (transparent >= 0) + { + /* + * Make transparent color white... + */ + + cmap[transparent][0] = 255; + cmap[transparent][1] = 255; + cmap[transparent][2] = 255; + } + + if (gray) + { + switch (secondary) + { + case IMAGE_CMYK : + for (i = ncolors - 1; i >= 0; i --) + ImageWhiteToCMYK(cmap[i], cmap[i], 1); + break; + case IMAGE_CMY : + for (i = ncolors - 1; i >= 0; i --) + ImageWhiteToCMY(cmap[i], cmap[i], 1); + break; + case IMAGE_BLACK : + for (i = ncolors - 1; i >= 0; i --) + ImageWhiteToBlack(cmap[i], cmap[i], 1); + break; + case IMAGE_WHITE : + break; + case IMAGE_RGB : + for (i = ncolors - 1; i >= 0; i --) + ImageWhiteToRGB(cmap[i], cmap[i], 1); + break; + } + + img->colorspace = secondary; + } + else + { + if (hue != 0 || saturation != 100) + for (i = ncolors - 1; i >= 0; i --) + ImageRGBAdjust(cmap[i], 1, saturation, hue); + + switch (primary) + { + case IMAGE_CMYK : + for (i = ncolors - 1; i >= 0; i --) + ImageRGBToCMYK(cmap[i], cmap[i], 1); + break; + case IMAGE_CMY : + for (i = ncolors - 1; i >= 0; i --) + ImageRGBToCMY(cmap[i], cmap[i], 1); + break; + case IMAGE_BLACK : + for (i = ncolors - 1; i >= 0; i --) + ImageRGBToBlack(cmap[i], cmap[i], 1); + break; + case IMAGE_WHITE : + for (i = ncolors - 1; i >= 0; i --) + ImageRGBToWhite(cmap[i], cmap[i], 1); + break; + case IMAGE_RGB : + break; + } + + img->colorspace = primary; + } + + if (lut) + { + bpp = ImageGetDepth(img); + + for (i = ncolors - 1; i >= 0; i --) + ImageLut(cmap[i], bpp, lut); + } + + img->xsize = (buf[5] << 8) | buf[4]; + img->ysize = (buf[7] << 8) | buf[6]; + + i = gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE); + fclose(fp); + return (i); + } + } +} + + +/* + * 'gif_read_cmap()' - Read the colormap from a GIF file... + */ + +static int /* O - -1 on error, 0 on success */ +gif_read_cmap(FILE *fp, /* I - File to read from */ + int ncolors, /* I - Number of colors in file */ + gif_cmap_t cmap, /* O - Colormap information */ + int *gray) /* IO - Is the image grayscale? */ +{ + int i; /* Looping var */ + + + /* + * Read the colormap... + */ + + for (i = 0; i < ncolors; i ++) + if (fread(cmap[i], 3, 1, fp) < 1) + return (-1); + + /* + * Check to see if the colormap is a grayscale ramp... + */ + + for (i = 0; i < ncolors; i ++) + if (cmap[i][0] != cmap[i][1] || cmap[i][1] != cmap[i][2]) + break; + + if (i == ncolors) + { + *gray = 1; + return (0); + } + + /* + * If this needs to be a grayscale image, convert the RGB values to + * luminance values... + */ + + if (*gray) + for (i = 0; i < ncolors; i ++) + cmap[i][0] = (cmap[i][0] * 31 + cmap[i][1] * 61 + cmap[i][2] * 8) / 100; + + return (0); +} + + +/* + * 'gif_get_block()' - Read a GIF data block... + */ + +static int /* O - Number characters read */ +gif_get_block(FILE *fp, /* I - File to read from */ + unsigned char *buf) /* I - Input buffer */ +{ + int count; /* Number of character to read */ + + + /* + * Read the count byte followed by the data from the file... + */ + + if ((count = getc(fp)) == EOF) + { + gif_eof = 1; + return (-1); + } + else if (count == 0) + gif_eof = 1; + else if (fread(buf, 1, count, fp) < count) + { + gif_eof = 1; + return (-1); + } + else + gif_eof = 0; + + return (count); +} + + +/* + * 'gif_get_code()' - Get a LZW code from the file... + */ + +static int /* O - LZW code */ +gif_get_code(FILE *fp, /* I - File to read from */ + int code_size, /* I - Size of code in bits */ + int first_time) /* I - 1 = first time, 0 = not first time */ +{ + unsigned i, j, /* Looping vars */ + ret; /* Return value */ + int count; /* Number of bytes read */ + static unsigned char buf[280]; /* Input buffer */ + static unsigned curbit, /* Current bit */ + lastbit, /* Last bit in buffer */ + done, /* Done with this buffer? */ + last_byte; /* Last byte in buffer */ + static unsigned char bits[8] = /* Bit masks for codes */ + { + 0x01, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80 + }; + + + if (first_time) + { + /* + * Just initialize the input buffer... + */ + + curbit = 0; + lastbit = 0; + done = 0; + + return (0); + } + + + if ((curbit + code_size) >= lastbit) + { + /* + * Don't have enough bits to hold the code... + */ + + if (done) + return (-1); /* Sorry, no more... */ + + /* + * Move last two bytes to front of buffer... + */ + + buf[0] = buf[last_byte - 2]; + buf[1] = buf[last_byte - 1]; + + /* + * Read in another buffer... + */ + + if ((count = gif_get_block (fp, buf + 2)) <= 0) + { + /* + * Whoops, no more data! + */ + + done = 1; + return (-1); + } + + /* + * Update buffer state... + */ + + last_byte = 2 + count; + curbit = (curbit - lastbit) + 16; + lastbit = last_byte * 8; + } + + ret = 0; + for (ret = 0, i = curbit + code_size - 1, j = code_size; + j > 0; + i --, j --) + ret = (ret << 1) | ((buf[i / 8] & bits[i & 7]) != 0); + + curbit += code_size; + + return ret; +} + + +/* + * 'gif_read_lzw()' - Read a byte from the LZW stream... + */ + +static int /* I - Byte from stream */ +gif_read_lzw(FILE *fp, /* I - File to read from */ + int first_time, /* I - 1 = first time, 0 = not first time */ + int input_code_size) /* I - Code size in bits */ +{ + int i, /* Looping var */ + code, /* Current code */ + incode; /* Input code */ + static short fresh = 0, /* 1 = empty buffers */ + code_size, /* Current code size */ + set_code_size, /* Initial code size set */ + max_code, /* Maximum code used */ + max_code_size, /* Maximum code size */ + firstcode, /* First code read */ + oldcode, /* Last code read */ + clear_code, /* Clear code for LZW input */ + end_code, /* End code for LZW input */ + table[2][4096], /* String table */ + stack[8192], /* Output stack */ + *sp; /* Current stack pointer */ + + + if (first_time) + { + /* + * Setup LZW state... + */ + + set_code_size = input_code_size; + code_size = set_code_size + 1; + clear_code = 1 << set_code_size; + end_code = clear_code + 1; + max_code_size = 2 * clear_code; + max_code = clear_code + 2; + + /* + * Initialize input buffers... + */ + + gif_get_code(fp, 0, 1); + + /* + * Wipe the decompressor table... + */ + + fresh = 1; + + for (i = 0; i < clear_code; i ++) + { + table[0][i] = 0; + table[1][i] = i; + } + + for (; i < 4096; i ++) + table[0][i] = table[1][0] = 0; + + sp = stack; + + return (0); + } + else if (fresh) + { + fresh = 0; + + do + firstcode = oldcode = gif_get_code(fp, code_size, 0); + while (firstcode == clear_code); + + return (firstcode); + } + + if (sp > stack) + return (*--sp); + + while ((code = gif_get_code (fp, code_size, 0)) >= 0) + { + if (code == clear_code) + { + for (i = 0; i < clear_code; i ++) + { + table[0][i] = 0; + table[1][i] = i; + } + + for (; i < 4096; i ++) + table[0][i] = table[1][i] = 0; + + code_size = set_code_size + 1; + max_code_size = 2 * clear_code; + max_code = clear_code + 2; + + sp = stack; + + firstcode = oldcode = gif_get_code(fp, code_size, 0); + + return (firstcode); + } + else if (code == end_code) + { + unsigned char buf[260]; + + + if (!gif_eof) + while (gif_get_block(fp, buf) > 0); + + return (-2); + } + + incode = code; + + if (code >= max_code) + { + *sp++ = firstcode; + code = oldcode; + } + + while (code >= clear_code) + { + *sp++ = table[1][code]; + if (code == table[0][code]) + return (255); + + code = table[0][code]; + } + + *sp++ = firstcode = table[1][code]; + code = max_code; + + if (code < 4096) + { + table[0][code] = oldcode; + table[1][code] = firstcode; + max_code ++; + + if (max_code >= max_code_size && max_code_size < 4096) + { + max_code_size *= 2; + code_size ++; + } + } + + oldcode = incode; + + if (sp > stack) + return (*--sp); + } + + return (code); +} + + +/* + * 'gif_read_image()' - Read a GIF image stream... + */ + +static int /* I - 0 = success, -1 = failure */ +gif_read_image(FILE *fp, /* I - Input file */ + image_t *img, /* I - Image pointer */ + gif_cmap_t cmap, /* I - Colormap */ + int interlace) /* I - Non-zero = interlaced image */ +{ + unsigned char code_size; /* Code size */ + ib_t *pixels, /* Pixel buffer */ + *temp; /* Current pixel */ + int xpos, /* Current X position */ + ypos, /* Current Y position */ + pass; /* Current pass */ + int pixel; /* Current pixel */ + int bpp; /* Bytes per pixel */ + static int xpasses[4] = { 8, 8, 4, 2 }, + ypasses[5] = { 0, 4, 2, 1, 999999 }; + + + bpp = ImageGetDepth(img); + pixels = calloc(bpp, img->xsize); + xpos = 0; + ypos = 0; + pass = 0; + code_size = getc(fp); + + if (gif_read_lzw(fp, 1, code_size) < 0) + return (-1); + + temp = pixels; + while ((pixel = gif_read_lzw(fp, 0, code_size)) >= 0) + { + switch (bpp) + { + case 4 : + temp[3] = cmap[pixel][3]; + case 3 : + temp[2] = cmap[pixel][2]; + case 2 : + temp[1] = cmap[pixel][1]; + default : + temp[0] = cmap[pixel][0]; + } + + xpos ++; + temp += bpp; + if (xpos == img->xsize) + { + ImagePutRow(img, 0, ypos, img->xsize, pixels); + + xpos = 0; + temp = pixels; + + if (interlace) + { + ypos += xpasses[pass]; + + if (ypos >= img->ysize) + { + pass ++; + + ypos = ypasses[pass]; + } + } + else + ypos ++; + } + + if (ypos >= img->ysize) + break; + } + + free(pixels); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image-jpeg.c b/filter/image-jpeg.c new file mode 100644 index 0000000000..31b0289599 --- /dev/null +++ b/filter/image-jpeg.c @@ -0,0 +1,190 @@ +/* + * "$Id$" + * + * JPEG image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadJPEG() - Read a JPEG image file. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + +#ifdef HAVE_LIBJPEG +# include /* JPEG/JFIF image definitions */ + + +/* + * 'ImageReadJPEG()' - Read a JPEG image file. + */ + +int /* O - Read status */ +ImageReadJPEG(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + struct jpeg_decompress_struct cinfo; /* Decompressor info */ + struct jpeg_error_mgr jerr; /* Error handler info */ + ib_t *in, /* Input pixels */ + *out; /* Output pixels */ + + + (void)secondary; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, fp); + jpeg_read_header(&cinfo, 1); + + cinfo.quantize_colors = 0; + + if (cinfo.num_components == 1) + { + cinfo.out_color_space = JCS_GRAYSCALE; + cinfo.out_color_components = 1; + cinfo.output_components = 1; + } + else + { + cinfo.out_color_space = JCS_RGB; + cinfo.out_color_components = 3; + cinfo.output_components = 3; + } + + jpeg_calc_output_dimensions(&cinfo); + + img->xsize = cinfo.output_width; + img->ysize = cinfo.output_height; + img->colorspace = primary; + + if (cinfo.X_density > 0 && cinfo.Y_density > 0 && cinfo.density_unit > 0) + { + if (cinfo.density_unit == 1) + { + img->xppi = cinfo.X_density; + img->yppi = cinfo.Y_density; + } + else + { + img->xppi = (int)((float)cinfo.X_density * 2.54); + img->yppi = (int)((float)cinfo.Y_density * 2.54); + } + } + + ImageSetMaxTiles(img, 0); + + in = malloc(img->xsize * cinfo.output_components); + if (primary < 0) + out = malloc(-img->xsize * primary); + else + out = malloc(img->xsize * primary); + + jpeg_start_decompress(&cinfo); + + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo, (JSAMPROW *)&in, (JDIMENSION)1); + + if ((saturation != 100 || hue != 0) && cinfo.output_components > 1) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + if ((primary == IMAGE_WHITE && cinfo.out_color_space == JCS_GRAYSCALE) || + (primary == IMAGE_RGB && cinfo.out_color_space == JCS_RGB)) + { + if (lut) + ImageLut(in, img->xsize * ImageGetDepth(img), lut); + + ImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, in); + } + else if (cinfo.out_color_space == JCS_GRAYSCALE) + { + switch (primary) + { + case IMAGE_BLACK : + ImageWhiteToBlack(in, out, img->xsize); + break; + case IMAGE_RGB : + ImageWhiteToRGB(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageWhiteToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * ImageGetDepth(img), lut); + + ImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out); + } + else + { + switch (primary) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * ImageGetDepth(img), lut); + + ImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out); + } + } + + free(in); + free(out); + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + fclose(fp); + + return (0); +} + + +#endif /* HAVE_LIBJPEG */ + + +/* + * End of "$Id$". + */ diff --git a/filter/image-photocd.c b/filter/image-photocd.c new file mode 100644 index 0000000000..57f1ee0008 --- /dev/null +++ b/filter/image-photocd.c @@ -0,0 +1,319 @@ +/* + * "$Id$" + * + * PhotoCD routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadPhotoCD() - Read a PhotoCD image file. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + + +/* + * PhotoCD support is currently limited to the 768x512 base image, which + * is only YCC encoded. Support for the higher resolution images will + * require a lot of extra code... + */ + +/* + * 'ImageReadPhotoCD()' - Read a PhotoCD image file. + */ + +int /* O - Read status */ +ImageReadPhotoCD(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + int x, y; /* Looping vars */ + int xdir, /* X direction */ + xstart; /* X starting point */ + int bpp; /* Bytes per pixel */ + int pass; /* Pass number */ + int rotation; /* 0 for 768x512, 1 for 512x768 */ + int temp, /* Adjusted luminance */ + temp2, /* Red, green, and blue values */ + cb, cr; /* Adjusted chroma values */ + ib_t *in, /* Input (YCC) pixels */ + *iy, /* Luminance */ + *icb, /* Blue chroma */ + *icr, /* Red chroma */ + *rgb, /* RGB */ + *rgbptr, /* Pointer into RGB data */ + *out; /* Output pixels */ + + + (void)secondary; + + /* + * Get the image orientation... + */ + + fseek(fp, 72, SEEK_SET); + rotation = (getc(fp) & 63) != 8; + + /* + * Seek to the start of the base image... + */ + + fseek(fp, 0x30000, SEEK_SET); + + /* + * Allocate and initialize... + */ + + img->colorspace = primary; + img->xppi = 128; + img->yppi = 128; + + if (rotation) + { + img->xsize = 512; + img->ysize = 768; + } + else + { + img->xsize = 768; + img->ysize = 512; + } + + ImageSetMaxTiles(img, 0); + + bpp = ImageGetDepth(img); + in = malloc(768 * 3); + out = malloc(768 * bpp); + + if (bpp > 1) + rgb = malloc(768 * 3); + + if (rotation) + { + xstart = 767 * bpp; + xdir = -2 * bpp; + } + else + { + xstart = 0; + xdir = 0; + } + + /* + * Read the image file... + */ + + for (y = 0; y < 512; y += 2) + { + /* + * Grab the next two scanlines: + * + * YYYYYYYYYYYYYYY... + * YYYYYYYYYYYYYYY... + * CbCbCb...CrCrCr... + */ + + if (fread(in, 1, 768 * 3, fp) < (768 * 3)) + { + /* + * Couldn't read a row of data - return an error! + */ + + free(in); + free(out); + + return (-1); + } + + /* + * Process the two scanlines... + */ + + for (pass = 0, iy = in; pass < 2; pass ++) + { + if (bpp == 1) + { + /* + * Just extract the luminance channel from the line and put it + * in the image... + */ + + if (primary == IMAGE_BLACK) + { + if (rotation) + { + for (rgbptr = out + xstart, x = 0; x < 768; x ++) + *rgbptr-- = 255 - *iy++; + + if (lut) + ImageLut(out, 768, lut); + + ImagePutCol(img, 511 - y - pass, 0, 768, out); + } + else + { + ImageWhiteToBlack(iy, out, 768); + + if (lut) + ImageLut(out, 768, lut); + + ImagePutRow(img, 0, y + pass, 768, out); + iy += 768; + } + } + else if (rotation) + { + for (rgbptr = out + xstart, x = 0; x < 768; x ++) + *rgbptr-- = 255 - *iy++; + + if (lut) + ImageLut(out, 768, lut); + + ImagePutCol(img, 511 - y - pass, 0, 768, out); + } + else + { + if (lut) + ImageLut(iy, 768, lut); + + ImagePutRow(img, 0, y + pass, 768, iy); + iy += 768; + } + } + else + { + /* + * Convert YCbCr to RGB... While every pixel gets a luminance + * value, adjacent pixels share chroma information. + */ + + for (x = 0, rgbptr = rgb + xstart, icb = in + 1536, icr = in + 1920; + x < 768; + x ++, iy ++, rgbptr += xdir) + { + if (!(x & 1)) + { + cb = (float)(*icb - 156); + cr = (float)(*icr - 137); + } + + temp = 92241 * (*iy); + + temp2 = (temp + 86706 * cr) / 65536; + if (temp2 < 0) + *rgbptr++ = 0; + else if (temp2 > 255) + *rgbptr++ = 255; + else + *rgbptr++ = temp2; + + temp2 = (temp - 25914 * cb - 44166 * cr) / 65536; + if (temp2 < 0) + *rgbptr++ = 0; + else if (temp2 > 255) + *rgbptr++ = 255; + else + *rgbptr++ = temp2; + + temp2 = (temp + 133434 * cb) / 65536; + if (temp2 < 0) + *rgbptr++ = 0; + else if (temp2 > 255) + *rgbptr++ = 255; + else + *rgbptr++ = temp2; + + if (x & 1) + { + icb ++; + icr ++; + } + } + + /* + * Adjust the hue and saturation if needed... + */ + + if (saturation != 100 || hue != 0) + ImageRGBAdjust(rgb, 768, saturation, hue); + + /* + * Then convert the RGB data to the appropriate colorspace and + * put it in the image... + */ + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(rgb, 768 * 3, lut); + + if (rotation) + ImagePutCol(img, 511 - y - pass, 0, 768, rgb); + else + ImagePutRow(img, 0, y + pass, 768, rgb); + } + else + { + switch (img->colorspace) + { + case IMAGE_CMY : + ImageRGBToCMY(rgb, out, 768); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(rgb, out, 768); + break; + } + + if (lut) + ImageLut(out, 768 * bpp, lut); + + if (rotation) + ImagePutCol(img, 511 - y - pass, 0, 768, out); + else + ImagePutRow(img, 0, y + pass, 768, out); + } + } + } + } + + /* + * Free memory and return... + */ + + free(in); + free(out); + if (bpp > 1) + free(rgb); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image-png.c b/filter/image-png.c new file mode 100644 index 0000000000..98626ac2e2 --- /dev/null +++ b/filter/image-png.c @@ -0,0 +1,205 @@ +/* + * "$Id$" + * + * PNG image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadPNG() - Read a PNG image file. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + +#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) +#include /* Portable Network Graphics (PNG) definitions */ + + +/* + * 'ImageReadPNG()' - Read a PNG image file. + */ + +int /* O - Read status */ +ImageReadPNG(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + int y; /* Looping var */ + png_structp pp; /* PNG read pointer */ + png_infop info; /* PNG info pointers */ + int bpp; /* Bytes per pixel */ + ib_t *in, /* Input pixels */ + *out; /* Output pixels */ + + + /* + * Setup the PNG data structures... + */ + + pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + info = png_create_info_struct(pp); + + /* + * Initialize the PNG read "engine"... + */ + + png_init_io(pp, fp); + + /* + * Get the image dimensions and load the output image... + */ + + png_read_info(pp, info); + + if (info->color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(pp); + + if (info->color_type == PNG_COLOR_TYPE_GRAY || + info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + img->colorspace = secondary; + else + img->colorspace = primary; + + img->xsize = info->width; + img->ysize = info->height; + + if (info->valid & PNG_INFO_pHYs && + info->phys_unit_type == PNG_RESOLUTION_METER) + { + img->xppi = (int)((float)info->x_pixels_per_unit * 0.0254); + img->yppi = (int)((float)info->y_pixels_per_unit * 0.0254); + } + + ImageSetMaxTiles(img, 0); + + if (info->bit_depth < 8) + { + png_set_packing(pp); + + if (info->valid & PNG_INFO_sBIT) + png_set_shift(pp, &(info->sig_bit)); + } + else if (info->bit_depth == 16) + png_set_strip_16(pp); + + if (info->color_type == PNG_COLOR_TYPE_GRAY || + info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + in = malloc(img->xsize); + else + in = malloc(img->xsize * 3); + + bpp = ImageGetDepth(img); + out = malloc(img->xsize * bpp); + + /* + * This doesn't work for interlaced PNG files... :( + */ + + for (y = 0; y < img->ysize; y ++) + { + if (info->color_type == PNG_COLOR_TYPE_GRAY || + info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + if (img->colorspace == IMAGE_WHITE) + png_read_row(pp, (png_bytep)out, NULL); + else + { + png_read_row(pp, (png_bytep)in, NULL); + + switch (img->colorspace) + { + case IMAGE_RGB : + ImageWhiteToRGB(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageWhiteToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageWhiteToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageWhiteToCMYK(in, out, img->xsize); + break; + } + } + } + else + { + if (img->colorspace == IMAGE_RGB) + { + png_read_row(pp, (png_bytep)out, NULL); + + if (saturation != 100 || hue != 0) + ImageRGBAdjust(out, img->xsize, saturation, hue); + } + else + { + png_read_row(pp, (png_bytep)in, NULL); + + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + } + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + + png_read_end(pp, info); + png_read_destroy(pp, info, NULL); + + fclose(fp); + + return (0); +} + + +#endif /* HAVE_LIBPNG && HAVE_LIBZ */ + + +/* + * End of "$Id$". + */ diff --git a/filter/image-pnm.c b/filter/image-pnm.c new file mode 100644 index 0000000000..11af3bd918 --- /dev/null +++ b/filter/image-pnm.c @@ -0,0 +1,288 @@ +/* + * "$Id$" + * + * Portable Any Map file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadPNM() - Read a PNM image file. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" +#include + + +/* + * 'ImageReadPNM()' - Read a PNM image file. + */ + +int /* O - Read status */ +ImageReadPNM(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + int x, y; /* Looping vars */ + int bpp; /* Bytes per pixel */ + ib_t *in, /* Input pixels */ + *inptr, /* Current input pixel */ + *out, /* Output pixels */ + *outptr, /* Current output pixel */ + bit; /* Bit in input line */ + char line[255], /* Input line */ + *lineptr; /* Pointer in line */ + int format, /* Format of PNM file */ + val, /* Pixel value */ + maxval; /* Maximum pixel value */ + + + /* + * Read the file header in the format: + * + * Pformat + * # comment1 + * # comment2 + * ... + * # commentN + * width + * height + * max sample + */ + + lineptr = fgets(line, sizeof(line), fp); + lineptr ++; + + format = atoi(lineptr); + while (isdigit(*lineptr)) + lineptr ++; + + while (lineptr != NULL && img->xsize == 0) + { + if (*lineptr == '\0' || *lineptr == '#') + lineptr = fgets(line, sizeof(line), fp); + else if (isdigit(*lineptr)) + { + img->xsize = atoi(lineptr); + while (isdigit(*lineptr)) + lineptr ++; + } + else + lineptr ++; + } + + while (lineptr != NULL && img->ysize == 0) + { + if (*lineptr == '\0' || *lineptr == '#') + lineptr = fgets(line, sizeof(line), fp); + else if (isdigit(*lineptr)) + { + img->ysize = atoi(lineptr); + while (isdigit(*lineptr)) + lineptr ++; + } + else + lineptr ++; + } + + if (format != 1 && format != 4) + { + maxval = 0; + + while (lineptr != NULL && maxval == 0) + { + if (*lineptr == '\0' || *lineptr == '#') + lineptr = fgets(line, sizeof(line), fp); + else if (isdigit(*lineptr)) + { + maxval = atoi(lineptr); + while (isdigit(*lineptr)) + lineptr ++; + } + else + lineptr ++; + } + } + else + maxval = 1; + + if (format == 1 || format == 2 || format == 4 || format == 5) + img->colorspace = secondary; + else + img->colorspace = primary; + + ImageSetMaxTiles(img, 0); + + bpp = ImageGetDepth(img); + in = malloc(img->xsize * 3); + out = malloc(img->xsize * bpp); + + /* + * Read the image file... + */ + + for (y = 0; y < img->ysize; y ++) + { + switch (format) + { + case 1 : + case 2 : + for (x = img->xsize, inptr = in; x > 0; x --, inptr ++) + if (fscanf(fp, "%d", &val) == 1) + *inptr = 255 * val / maxval; + break; + + case 3 : + for (x = img->xsize, inptr = in; x > 0; x --, inptr += 3) + { + if (fscanf(fp, "%d", &val) == 1) + inptr[0] = 255 * val / maxval; + if (fscanf(fp, "%d", &val) == 1) + inptr[1] = 255 * val / maxval; + if (fscanf(fp, "%d", &val) == 1) + inptr[2] = 255 * val / maxval; + } + break; + + case 4 : + fread(out, (img->xsize + 7) / 8, 1, fp); + for (x = img->xsize, inptr = in, outptr = out, bit = 128; + x > 0; + x --, inptr ++) + { + if (*outptr & bit) + *inptr = 255; + else + *inptr = 0; + + if (bit > 1) + bit >>= 1; + else + { + bit = 128; + inptr ++; + } + } + break; + + case 5 : + fread(in, img->xsize, 1, fp); + break; + + case 6 : + fread(in, img->xsize, 3, fp); + break; + } + + switch (format) + { + case 1 : + case 2 : + case 4 : + case 5 : + if (img->colorspace == IMAGE_WHITE) + { + if (lut) + ImageLut(in, img->xsize, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_RGB : + ImageWhiteToRGB(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageWhiteToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageWhiteToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + break; + + default : + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(in, img->xsize * 3, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + break; + } + } + + free(in); + free(out); + + fclose(fp); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image-sgi.c b/filter/image-sgi.c new file mode 100644 index 0000000000..cf840c5337 --- /dev/null +++ b/filter/image-sgi.c @@ -0,0 +1,267 @@ +/* + * "$Id$" + * + * SGI image file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadSGI() - Read a SGI image file. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" +#include "image-sgi.h" + + +/* + * 'ImageReadSGI()' - Read a SGI image file. + */ + +int /* O - Read status */ +ImageReadSGI(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + int i, y; /* Looping vars */ + int bpp; /* Bytes per pixel */ + sgi_t *sgip; /* SGI image file */ + ib_t *in, /* Input pixels */ + *inptr, /* Current input pixel */ + *out; /* Output pixels */ + unsigned short *rows[4], /* Row pointers for image data */ + *red, + *green, + *blue, + *gray, + *alpha; + + + /* + * Setup the SGI file... + */ + + sgip = sgiOpenFile(fp, SGI_READ, 0, 0, 0, 0, 0); + + /* + * Get the image dimensions and load the output image... + */ + + if (sgip->zsize < 3) + img->colorspace = secondary; + else + img->colorspace = primary; + + img->xsize = sgip->xsize; + img->ysize = sgip->ysize; + + ImageSetMaxTiles(img, 0); + + bpp = ImageGetDepth(img); + in = malloc(img->xsize * sgip->zsize); + out = malloc(img->xsize * bpp); + + rows[0] = calloc(img->xsize * sgip->zsize, sizeof(unsigned short)); + for (i = 1; i < sgip->zsize; i ++) + rows[i] = rows[0] + i * img->xsize; + + /* + * Read the SGI image file... + */ + + for (y = 0; y < img->ysize; y ++) + { + for (i = 0; i < sgip->zsize; i ++) + sgiGetRow(sgip, rows[i], img->ysize - 1 - y, i); + + switch (sgip->zsize) + { + case 1 : + if (sgip->bpp == 1) + for (i = img->xsize - 1, gray = rows[0], inptr = in; + i >= 0; + i --) + { + *inptr++ = *gray++; + } + else + for (i = img->xsize - 1, gray = rows[0], inptr = in; + i >= 0; + i --) + { + *inptr++ = (*gray++) / 256 + 128; + } + break; + case 2 : + if (sgip->bpp == 1) + for (i = img->xsize - 1, gray = rows[0], alpha = rows[1], inptr = in; + i >= 0; + i --) + { + *inptr++ = (*gray++) * (*alpha++) / 255; + } + else + for (i = img->xsize - 1, gray = rows[0], alpha = rows[1], inptr = in; + i >= 0; + i --) + { + *inptr++ = ((*gray++) / 256 + 128) * (*alpha++) / 32767; + } + break; + case 3 : + if (sgip->bpp == 1) + for (i = img->xsize - 1, red = rows[0], green = rows[1], + blue = rows[2], inptr = in; + i >= 0; + i --) + { + *inptr++ = *red++; + *inptr++ = *green++; + *inptr++ = *blue++; + } + else + for (i = img->xsize - 1, red = rows[0], green = rows[1], + blue = rows[2], inptr = in; + i >= 0; + i --) + { + *inptr++ = (*red++) / 256 + 128; + *inptr++ = (*green++) / 256 + 128; + *inptr++ = (*blue++) / 256 + 128; + } + break; + case 4 : + if (sgip->bpp == 1) + for (i = img->xsize - 1, red = rows[0], green = rows[1], + blue = rows[2], alpha = rows[3], inptr = in; + i >= 0; + i --) + { + *inptr++ = (*red++) * (*alpha) / 255; + *inptr++ = (*green++) * (*alpha) / 255; + *inptr++ = (*blue++) * (*alpha++) / 255; + } + else + for (i = img->xsize - 1, red = rows[0], green = rows[1], + blue = rows[2], inptr = in; + i >= 0; + i --) + { + *inptr++ = ((*red++) / 256 + 128) * (*alpha) / 32767; + *inptr++ = ((*green++) / 256 + 128) * (*alpha) / 32767; + *inptr++ = ((*blue++) / 256 + 128) * (*alpha++) / 32767; + } + break; + } + + if (sgip->zsize < 3) + { + if (img->colorspace == IMAGE_WHITE) + { + if (lut) + ImageLut(in, img->xsize, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_RGB : + ImageWhiteToRGB(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageWhiteToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageWhiteToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + else + { + if (img->colorspace == IMAGE_RGB) + { + if (saturation != 100 || hue != 0) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + if (lut) + ImageLut(in, img->xsize * 3, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + } + + free(in); + free(out); + free(rows[0]); + + sgiClose(sgip); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image-sgi.h b/filter/image-sgi.h new file mode 100644 index 0000000000..0b8220d32e --- /dev/null +++ b/filter/image-sgi.h @@ -0,0 +1,94 @@ +/* + * "$Id$" + * + * SGI image file format library definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _SGI_H_ +# define _SGI_H_ + +# include +# include +# include + +# ifdef __cplusplus +extern "C" { +# endif + + +/* + * Constants... + */ + +# define SGI_MAGIC 474 /* Magic number in image file */ + +# define SGI_READ 0 /* Read from an SGI image file */ +# define SGI_WRITE 1 /* Write to an SGI image file */ + +# define SGI_COMP_NONE 0 /* No compression */ +# define SGI_COMP_RLE 1 /* Run-length encoding */ +# define SGI_COMP_ARLE 2 /* Agressive run-length encoding */ + + +/* + * Image structure... + */ + +typedef struct +{ + FILE *file; /* Image file */ + int mode, /* File open mode */ + bpp, /* Bytes per pixel/channel */ + comp; /* Compression */ + unsigned short xsize, /* Width in pixels */ + ysize, /* Height in pixels */ + zsize; /* Number of channels */ + long firstrow, /* File offset for first row */ + nextrow, /* File offset for next row */ + **table, /* Offset table for compression */ + **length; /* Length table for compression */ + unsigned short *arle_row; /* Advanced RLE compression buffer */ + long arle_offset, /* Advanced RLE buffer offset */ + arle_length; /* Advanced RLE buffer length */ +} sgi_t; + + +/* + * Prototypes... + */ + +extern int sgiClose(sgi_t *sgip); +extern int sgiGetRow(sgi_t *sgip, unsigned short *row, int y, int z); +extern sgi_t *sgiOpen(char *filename, int mode, int comp, int bpp, + int xsize, int ysize, int zsize); +extern sgi_t *sgiOpenFile(FILE *file, int mode, int comp, int bpp, + int xsize, int ysize, int zsize); +extern int sgiPutRow(sgi_t *sgip, unsigned short *row, int y, int z); + +# ifdef __cplusplus +} +# endif +#endif /* !_SGI_H_ */ + +/* + * End of "$Id$". + */ diff --git a/filter/image-sgilib.c b/filter/image-sgilib.c new file mode 100644 index 0000000000..c9f3d57d48 --- /dev/null +++ b/filter/image-sgilib.c @@ -0,0 +1,857 @@ +/* + * "$Id$" + * + * SGI image file format library routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * sgiClose() - Close an SGI image file. + * sgiGetRow() - Get a row of image data from a file. + * sgiOpen() - Open an SGI image file for reading or writing. + * sgiOpenFile() - Open an SGI image file for reading or writing. + * sgiPutRow() - Put a row of image data to a file. + * getlong() - Get a 32-bit big-endian integer. + * getshort() - Get a 16-bit big-endian integer. + * putlong() - Put a 32-bit big-endian integer. + * putshort() - Put a 16-bit big-endian integer. + * read_rle8() - Read 8-bit RLE data. + * read_rle16() - Read 16-bit RLE data. + * write_rle8() - Write 8-bit RLE data. + * write_rle16() - Write 16-bit RLE data. + */ + +#include "image-sgi.h" + + +/* + * Local functions... + */ + +static int getlong(FILE *); +static int getshort(FILE *); +static int putlong(long, FILE *); +static int putshort(unsigned short, FILE *); +static int read_rle8(FILE *, unsigned short *, int); +static int read_rle16(FILE *, unsigned short *, int); +static int write_rle8(FILE *, unsigned short *, int); +static int write_rle16(FILE *, unsigned short *, int); + + +/* + * 'sgiClose()' - Close an SGI image file. + */ + +int +sgiClose(sgi_t *sgip) /* I - SGI image */ +{ + int i; /* Return status */ + long *offset; /* Looping var for offset table */ + + + if (sgip == NULL) + return (-1); + + if (sgip->mode == SGI_WRITE && sgip->comp != SGI_COMP_NONE) + { + /* + * Write the scanline offset table to the file... + */ + + fseek(sgip->file, 512, SEEK_SET); + + for (i = sgip->ysize * sgip->zsize, offset = sgip->table[0]; + i > 0; + i --, offset ++) + if (putlong(offset[0], sgip->file) < 0) + return (-1); + + for (i = sgip->ysize * sgip->zsize, offset = sgip->length[0]; + i > 0; + i --, offset ++) + if (putlong(offset[0], sgip->file) < 0) + return (-1); + } + + if (sgip->table != NULL) + { + free(sgip->table[0]); + free(sgip->table); + } + + if (sgip->length != NULL) + { + free(sgip->length[0]); + free(sgip->length); + } + + if (sgip->comp == SGI_COMP_ARLE) + free(sgip->arle_row); + + i = fclose(sgip->file); + free(sgip); + + return (i); +} + + +/* + * 'sgiGetRow()' - Get a row of image data from a file. + */ + +int +sgiGetRow(sgi_t *sgip, /* I - SGI image */ + unsigned short *row, /* O - Row to read */ + int y, /* I - Line to read */ + int z) /* I - Channel to read */ +{ + int x; /* X coordinate */ + long offset; /* File offset */ + + + if (sgip == NULL || + row == NULL || + y < 0 || y >= sgip->ysize || + z < 0 || z >= sgip->zsize) + return (-1); + + switch (sgip->comp) + { + case SGI_COMP_NONE : + /* + * Seek to the image row - optimize buffering by only seeking if + * necessary... + */ + + offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp; + if (offset != ftell(sgip->file)) + fseek(sgip->file, offset, SEEK_SET); + + if (sgip->bpp == 1) + { + for (x = sgip->xsize; x > 0; x --, row ++) + *row = getc(sgip->file); + } + else + { + for (x = sgip->xsize; x > 0; x --, row ++) + *row = getshort(sgip->file); + } + break; + + case SGI_COMP_RLE : + offset = sgip->table[z][y]; + if (offset != ftell(sgip->file)) + fseek(sgip->file, offset, SEEK_SET); + + if (sgip->bpp == 1) + return (read_rle8(sgip->file, row, sgip->xsize)); + else + return (read_rle16(sgip->file, row, sgip->xsize)); + } + + return (0); +} + + +/* + * 'sgiOpen()' - Open an SGI image file for reading or writing. + */ + +sgi_t * +sgiOpen(char *filename, /* I - File to open */ + int mode, /* I - Open mode (SGI_READ or SGI_WRITE) */ + int comp, /* I - Type of compression */ + int bpp, /* I - Bytes per pixel */ + int xsize, /* I - Width of image in pixels */ + int ysize, /* I - Height of image in pixels */ + int zsize) /* I - Number of channels */ +{ + sgi_t *sgip; /* New SGI image file */ + FILE *file; /* Image file pointer */ + + + if (mode == SGI_READ) + file = fopen(filename, "rb"); + else + file = fopen(filename, "wb+"); + + if (file == NULL) + return (NULL); + + if ((sgip = sgiOpenFile(file, mode, comp, bpp, xsize, ysize, zsize)) == NULL) + fclose(file); + + return (sgip); +} + + +/* + * 'sgiOpenFile()' - Open an SGI image file for reading or writing. + */ + +sgi_t * +sgiOpenFile(FILE *file, /* I - File to open */ + int mode, /* I - Open mode (SGI_READ or SGI_WRITE) */ + int comp, /* I - Type of compression */ + int bpp, /* I - Bytes per pixel */ + int xsize, /* I - Width of image in pixels */ + int ysize, /* I - Height of image in pixels */ + int zsize) /* I - Number of channels */ +{ + int i, j; /* Looping var */ + char name[80]; /* Name of file in image header */ + short magic; /* Magic number */ + sgi_t *sgip; /* New image pointer */ + + + if ((sgip = calloc(sizeof(sgi_t), 1)) == NULL) + return (NULL); + + sgip->file = file; + + switch (mode) + { + case SGI_READ : + sgip->mode = SGI_READ; + + magic = getshort(sgip->file); + if (magic != SGI_MAGIC) + { + free(sgip); + return (NULL); + } + + sgip->comp = getc(sgip->file); + sgip->bpp = getc(sgip->file); + getshort(sgip->file); /* Dimensions */ + sgip->xsize = getshort(sgip->file); + sgip->ysize = getshort(sgip->file); + sgip->zsize = getshort(sgip->file); + getlong(sgip->file); /* Minimum pixel */ + getlong(sgip->file); /* Maximum pixel */ + + if (sgip->comp) + { + /* + * This file is compressed; read the scanline tables... + */ + + fseek(sgip->file, 512, SEEK_SET); + + sgip->table = calloc(sgip->zsize, sizeof(long *)); + sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long)); + for (i = 1; i < sgip->zsize; i ++) + sgip->table[i] = sgip->table[0] + i * sgip->ysize; + + for (i = 0; i < sgip->zsize; i ++) + for (j = 0; j < sgip->ysize; j ++) + sgip->table[i][j] = getlong(sgip->file); + } + break; + + case SGI_WRITE : + if (xsize < 1 || + ysize < 1 || + zsize < 1 || + bpp < 1 || bpp > 2 || + comp < SGI_COMP_NONE || comp > SGI_COMP_ARLE) + { + free(sgip); + return (NULL); + } + + sgip->mode = SGI_WRITE; + + putshort(SGI_MAGIC, sgip->file); + putc((sgip->comp = comp) != 0, sgip->file); + putc(sgip->bpp = bpp, sgip->file); + putshort(3, sgip->file); /* Dimensions */ + putshort(sgip->xsize = xsize, sgip->file); + putshort(sgip->ysize = ysize, sgip->file); + putshort(sgip->zsize = zsize, sgip->file); + if (bpp == 1) + { + putlong(0, sgip->file); /* Minimum pixel */ + putlong(255, sgip->file); /* Maximum pixel */ + } + else + { + putlong(-32768, sgip->file); /* Minimum pixel */ + putlong(32767, sgip->file); /* Maximum pixel */ + } + putlong(0, sgip->file); /* Reserved */ + + memset(name, 0, sizeof(name)); + fwrite(name, sizeof(name), 1, sgip->file); + + for (i = 0; i < 102; i ++) + putlong(0, sgip->file); + + switch (comp) + { + case SGI_COMP_NONE : /* No compression */ + /* + * This file is uncompressed. To avoid problems with sparse files, + * we need to write blank pixels for the entire image... + */ + + if (bpp == 1) + { + for (i = xsize * ysize * zsize; i > 0; i --) + putc(0, sgip->file); + } + else + { + for (i = xsize * ysize * zsize; i > 0; i --) + putshort(0, sgip->file); + } + break; + + case SGI_COMP_ARLE : /* Aggressive RLE */ + sgip->arle_row = calloc(xsize, sizeof(unsigned short)); + sgip->arle_offset = 0; + + case SGI_COMP_RLE : /* Run-Length Encoding */ + /* + * This file is compressed; write the (blank) scanline tables... + */ + + for (i = 2 * ysize * zsize; i > 0; i --) + putlong(0, sgip->file); + + sgip->firstrow = ftell(sgip->file); + sgip->nextrow = ftell(sgip->file); + sgip->table = calloc(sgip->zsize, sizeof(long *)); + sgip->table[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long)); + for (i = 1; i < sgip->zsize; i ++) + sgip->table[i] = sgip->table[0] + i * sgip->ysize; + sgip->length = calloc(sgip->zsize, sizeof(long *)); + sgip->length[0] = calloc(sgip->ysize * sgip->zsize, sizeof(long)); + for (i = 1; i < sgip->zsize; i ++) + sgip->length[i] = sgip->length[0] + i * sgip->ysize; + break; + } + break; + + default : + free(sgip); + return (NULL); + } + + return (sgip); +} + + +/* + * 'sgiPutRow()' - Put a row of image data to a file. + */ + +int +sgiPutRow(sgi_t *sgip, /* I - SGI image */ + unsigned short *row, /* I - Row to write */ + int y, /* I - Line to write */ + int z) /* I - Channel to write */ +{ + int x; /* X coordinate */ + long offset; /* File offset */ + + + if (sgip == NULL || + row == NULL || + y < 0 || y >= sgip->ysize || + z < 0 || z >= sgip->zsize) + return (-1); + + switch (sgip->comp) + { + case SGI_COMP_NONE : + /* + * Seek to the image row - optimize buffering by only seeking if + * necessary... + */ + + offset = 512 + (y + z * sgip->ysize) * sgip->xsize * sgip->bpp; + if (offset != ftell(sgip->file)) + fseek(sgip->file, offset, SEEK_SET); + + if (sgip->bpp == 1) + { + for (x = sgip->xsize; x > 0; x --, row ++) + putc(*row, sgip->file); + } + else + { + for (x = sgip->xsize; x > 0; x --, row ++) + putshort(*row, sgip->file); + } + break; + + case SGI_COMP_ARLE : + if (sgip->table[z][y] != 0) + return (-1); + + /* + * First check the last row written... + */ + + if (sgip->arle_offset > 0) + { + for (x = 0; x < sgip->xsize; x ++) + if (row[x] != sgip->arle_row[x]) + break; + + if (x == sgip->xsize) + { + sgip->table[z][y] = sgip->arle_offset; + sgip->length[z][y] = sgip->arle_length; + return (0); + } + } + + /* + * If that didn't match, search all the previous rows... + */ + + fseek(sgip->file, sgip->firstrow, SEEK_SET); + + if (sgip->bpp == 1) + { + for (;;) + { + sgip->arle_offset = ftell(sgip->file); + if ((sgip->arle_length = read_rle8(sgip->file, sgip->arle_row, sgip->xsize)) < 0) + { + x = 0; + break; + } + + if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0) + { + x = sgip->xsize; + break; + } + } + } + else + { + for (;;) + { + sgip->arle_offset = ftell(sgip->file); + if ((sgip->arle_length = read_rle16(sgip->file, sgip->arle_row, sgip->xsize)) < 0) + { + x = 0; + break; + } + + if (memcmp(row, sgip->arle_row, sgip->xsize * sizeof(unsigned short)) == 0) + { + x = sgip->xsize; + break; + } + } + } + + if (x == sgip->xsize) + { + sgip->table[z][y] = sgip->arle_offset; + sgip->length[z][y] = sgip->arle_length; + return (0); + } + else + fseek(sgip->file, 0, SEEK_END); /* Clear EOF */ + + case SGI_COMP_RLE : + if (sgip->table[z][y] != 0) + return (-1); + + offset = sgip->table[z][y] = sgip->nextrow; + + if (offset != ftell(sgip->file)) + fseek(sgip->file, offset, SEEK_SET); + + if (sgip->bpp == 1) + x = write_rle8(sgip->file, row, sgip->xsize); + else + x = write_rle16(sgip->file, row, sgip->xsize); + + if (sgip->comp == SGI_COMP_ARLE) + { + sgip->arle_offset = offset; + sgip->arle_length = x; + memcpy(sgip->arle_row, row, sgip->xsize * sizeof(unsigned short)); + } + + sgip->nextrow = ftell(sgip->file); + sgip->length[z][y] = x; + + return (x); + } + + return (0); +} + + +/* + * 'getlong()' - Get a 32-bit big-endian integer. + */ + +static int +getlong(FILE *fp) /* I - File to read from */ +{ + unsigned char b[4]; + + + fread(b, 4, 1, fp); + return ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]); +} + + +/* + * 'getshort()' - Get a 16-bit big-endian integer. + */ + +static int +getshort(FILE *fp) /* I - File to read from */ +{ + unsigned char b[2]; + + + fread(b, 2, 1, fp); + return ((b[0] << 8) | b[1]); +} + + +/* + * 'putlong()' - Put a 32-bit big-endian integer. + */ + +static int +putlong(long n, /* I - Long to write */ + FILE *fp) /* I - File to write to */ +{ + if (putc(n >> 24, fp) == EOF) + return (EOF); + if (putc(n >> 16, fp) == EOF) + return (EOF); + if (putc(n >> 8, fp) == EOF) + return (EOF); + if (putc(n, fp) == EOF) + return (EOF); + else + return (0); +} + + +/* + * 'putshort()' - Put a 16-bit big-endian integer. + */ + +static int +putshort(unsigned short n, /* I - Short to write */ + FILE *fp) /* I - File to write to */ +{ + if (putc(n >> 8, fp) == EOF) + return (EOF); + if (putc(n, fp) == EOF) + return (EOF); + else + return (0); +} + + +/* + * 'read_rle8()' - Read 8-bit RLE data. + */ + +static int +read_rle8(FILE *fp, /* I - File to read from */ + unsigned short *row, /* O - Data */ + int xsize) /* I - Width of data in pixels */ +{ + int i, /* Looping var */ + ch, /* Current character */ + count, /* RLE count */ + length; /* Number of bytes read... */ + + + length = 0; + + while (xsize > 0) + { + if ((ch = getc(fp)) == EOF) + return (-1); + length ++; + + count = ch & 127; + if (count == 0) + break; + + if (ch & 128) + { + for (i = 0; i < count; i ++, row ++, xsize --, length ++) + *row = getc(fp); + } + else + { + ch = getc(fp); + length ++; + for (i = 0; i < count; i ++, row ++, xsize --) + *row = ch; + } + } + + return (xsize > 0 ? -1 : length); +} + + +/* + * 'read_rle16()' - Read 16-bit RLE data. + */ + +static int +read_rle16(FILE *fp, /* I - File to read from */ + unsigned short *row, /* O - Data */ + int xsize)/* I - Width of data in pixels */ +{ + int i, /* Looping var */ + ch, /* Current character */ + count, /* RLE count */ + length; /* Number of bytes read... */ + + + length = 0; + + while (xsize > 0) + { + if ((ch = getshort(fp)) == EOF) + return (-1); + length ++; + + count = ch & 127; + if (count == 0) + break; + + if (ch & 128) + { + for (i = 0; i < count; i ++, row ++, xsize --, length ++) + *row = getshort(fp); + } + else + { + ch = getshort(fp); + length ++; + for (i = 0; i < count; i ++, row ++, xsize --) + *row = ch; + } + } + + return (xsize > 0 ? -1 : length * 2); +} + + +/* + * 'write_rle8()' - Write 8-bit RLE data. + */ + +static int +write_rle8(FILE *fp, /* I - File to write to */ + unsigned short *row, /* I - Data */ + int xsize)/* I - Width of data in pixels */ +{ + int length, + count, + i, + x; + unsigned short *start, + repeat; + + + for (x = xsize, length = 0; x > 0;) + { + start = row; + row += 2; + x -= 2; + + while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) + { + row ++; + x --; + } + + row -= 2; + x += 2; + + count = row - start; + while (count > 0) + { + i = count > 126 ? 126 : count; + count -= i; + + if (putc(128 | i, fp) == EOF) + return (-1); + length ++; + + while (i > 0) + { + if (putc(*start, fp) == EOF) + return (-1); + start ++; + i --; + length ++; + } + } + + if (x <= 0) + break; + + start = row; + repeat = row[0]; + + row ++; + x --; + + while (x > 0 && *row == repeat) + { + row ++; + x --; + } + + count = row - start; + while (count > 0) + { + i = count > 126 ? 126 : count; + count -= i; + + if (putc(i, fp) == EOF) + return (-1); + length ++; + + if (putc(repeat, fp) == EOF) + return (-1); + length ++; + } + } + + length ++; + + if (putc(0, fp) == EOF) + return (-1); + else + return (length); +} + + +/* + * 'write_rle16()' - Write 16-bit RLE data. + */ + +static int +write_rle16(FILE *fp, /* I - File to write to */ + unsigned short *row, /* I - Data */ + int xsize)/* I - Width of data in pixels */ +{ + int length, + count, + i, + x; + unsigned short *start, + repeat; + + + for (x = xsize, length = 0; x > 0;) + { + start = row; + row += 2; + x -= 2; + + while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) + { + row ++; + x --; + } + + row -= 2; + x += 2; + + count = row - start; + while (count > 0) + { + i = count > 126 ? 126 : count; + count -= i; + + if (putshort(128 | i, fp) == EOF) + return (-1); + length ++; + + while (i > 0) + { + if (putshort(*start, fp) == EOF) + return (-1); + start ++; + i --; + length ++; + } + } + + if (x <= 0) + break; + + start = row; + repeat = row[0]; + + row ++; + x --; + + while (x > 0 && *row == repeat) + { + row ++; + x --; + } + + count = row - start; + while (count > 0) + { + i = count > 126 ? 126 : count; + count -= i; + + if (putshort(i, fp) == EOF) + return (-1); + length ++; + + if (putshort(repeat, fp) == EOF) + return (-1); + length ++; + } + } + + length ++; + + if (putshort(0, fp) == EOF) + return (-1); + else + return (2 * length); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image-sun.c b/filter/image-sun.c new file mode 100644 index 0000000000..1e7bb5bc46 --- /dev/null +++ b/filter/image-sun.c @@ -0,0 +1,376 @@ +/* + * "$Id$" + * + * Sun Raster image file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadSunRaster() - Read a SunRaster image file. + * read_unsigned() - Read a 32-bit unsigned integer. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + + +#define RAS_MAGIC 0x59a66a95 + + /* Sun supported ras_type's */ +#define RT_OLD 0 /* Raw pixrect image in 68000 byte order */ +#define RT_STANDARD 1 /* Raw pixrect image in 68000 byte order */ +#define RT_BYTE_ENCODED 2 /* Run-length compression of bytes */ +#define RT_FORMAT_RGB 3 /* XRGB or RGB instead of XBGR or BGR */ +#define RT_EXPERIMENTAL 0xffff /* Reserved for testing */ + + /* Sun registered ras_maptype's */ +#define RMT_RAW 2 + /* Sun supported ras_maptype's */ +#define RMT_NONE 0 /* ras_maplength is expected to be 0 */ +#define RMT_EQUAL_RGB 1 /* red[ras_maplength/3],green[],blue[] */ + +#define RAS_RLE 0x80 + +/* + * NOTES: + * Each line of the image is rounded out to a multiple of 16 bits. + * This corresponds to the rounding convention used by the memory pixrect + * package (/usr/include/pixrect/memvar.h) of the SunWindows system. + * The ras_encoding field (always set to 0 by Sun's supported software) + * was renamed to ras_length in release 2.0. As a result, rasterfiles + * of type 0 generated by the old software claim to have 0 length; for + * compatibility, code reading rasterfiles must be prepared to compute the + * true length from the width, height, and depth fields. + */ + +/* + * Local functions... + */ + +static unsigned read_unsigned(FILE *fp); + + +/* + * 'ImageReadSunRaster()' - Read a SunRaster image file. + */ + +int /* O - Read status */ +ImageReadSunRaster(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary,/* I - Secondary choice for colorspace */ + int saturation,/* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + int i, x, y, + bpp, /* Bytes per pixel */ + scanwidth, + run_count, + run_value; + ib_t *in, + *out, + *scanline, + *scanptr, + *p, + bit; + unsigned ras_depth, /* depth (1, 8, or 24 bits) of pixel */ + ras_type, /* type of file; see RT_* below */ + ras_maplength; /* length (bytes) of following map */ + unsigned char cmap[3][256]; /* colormap */ + + + /* + * Read the header; we already know that this is a raster file (ImageOpen + * checks this) so we don't need to check the magic number again. + */ + + read_unsigned(fp); /* Skip magic */ + img->xsize = read_unsigned(fp); + img->ysize = read_unsigned(fp); + ras_depth = read_unsigned(fp); + /* ras_length */read_unsigned(fp); + ras_type = read_unsigned(fp); + /* ras_maptype*/read_unsigned(fp); + ras_maplength = read_unsigned(fp); + + if (ras_maplength > 0) + { + fread(cmap[0], 1, ras_maplength / 3, fp); + fread(cmap[1], 1, ras_maplength / 3, fp); + fread(cmap[2], 1, ras_maplength / 3, fp); + } + + /* + * Compute the width of each line and allocate memory as needed... + */ + + scanwidth = (img->xsize * ras_depth + 7) / 8; + if (scanwidth & 1) + scanwidth ++; + + if (ras_depth < 24 && ras_maplength == 0) + { + img->colorspace = secondary; + in = malloc(img->xsize + 1); + } + else + { + img->colorspace = primary; + in = malloc(img->xsize * 3 + 1); + } + + bpp = ImageGetDepth(img); + out = malloc(img->xsize * bpp); + scanline = malloc(scanwidth); + run_count = 0; + + for (y = 0; y < img->ysize; y ++) + { + if (ras_depth != 8 || ras_maplength > 0) + p = scanline; + else + p = in; + + if (ras_type != RT_BYTE_ENCODED) + fread(p, scanwidth, 1, fp); + else + { + for (i = scanwidth; i > 0; i --, p ++) + { + if (run_count > 0) + { + *p = run_value; + run_count --; + } + else + { + run_value = getc(fp); + + if (run_value == RAS_RLE) + { + run_count = getc(fp); + if (run_count == 0) + *p = RAS_RLE; + else + run_value = *p = getc(fp); + } + else + *p = run_value; + } + } + } + + if (ras_depth == 1 && ras_maplength == 0) + { + /* + * 1-bit B&W image... + */ + + for (x = img->xsize, bit = 128, scanptr = scanline, p = in; + x > 0; + x --, p ++) + { + if (*scanptr & bit) + *p = 255; + else + *p = 0; + + if (bit > 1) + { + bit = 128; + scanptr ++; + } + else + bit >>= 1; + } + } + else if (ras_depth == 1) + { + /* + * 1-bit colormapped image... + */ + + for (x = img->xsize, bit = 128, scanptr = scanline, p = in; + x > 0; + x --) + { + if (*scanptr & bit) + { + *p++ = cmap[0][1]; + *p++ = cmap[1][1]; + *p++ = cmap[2][1]; + } + else + { + *p++ = cmap[0][0]; + *p++ = cmap[1][0]; + *p++ = cmap[2][0]; + } + + if (bit > 1) + { + bit = 128; + scanptr ++; + } + else + bit >>= 1; + } + } + else if (ras_depth == 8 && ras_maplength > 0) + { + /* + * 8-bit colormapped image. + */ + + for (x = img->xsize, scanptr = scanline, p = in; + x > 0; + x --) + { + *p++ = cmap[0][*scanptr]; + *p++ = cmap[1][*scanptr]; + *p++ = cmap[2][*scanptr++]; + } + } + else if (ras_depth == 24 && ras_type != RT_FORMAT_RGB) + { + /* + * Convert BGR to RGB... + */ + + for (x = img->xsize, scanptr = scanline, p = in; + x > 0; + x --, scanptr += 3) + { + *p++ = scanptr[2]; + *p++ = scanptr[1]; + *p++ = scanptr[0]; + } + } + + if (bpp == 1) + { + if (img->colorspace == IMAGE_WHITE) + { + if (lut) + ImageLut(in, img->xsize, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_RGB : + ImageWhiteToRGB(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageWhiteToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageWhiteToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + else + { + if (img->colorspace == IMAGE_RGB) + { + if (saturation != 100 || hue != 0) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + if (lut) + ImageLut(in, img->xsize * 3, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + } + + free(scanline); + free(in); + free(out); + + fclose(fp); + + return (0); +} + + +/* + * 'read_unsigned()' - Read a 32-bit unsigned integer. + */ + +static unsigned /* O - Integer from file */ +read_unsigned(FILE *fp) /* I - File to read from */ +{ + unsigned v; /* Integer from file */ + + + v = getc(fp); + v = (v << 8) | getc(fp); + v = (v << 8) | getc(fp); + v = (v << 8) | getc(fp); + + return (v); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image-tiff.c b/filter/image-tiff.c new file mode 100644 index 0000000000..260d44b767 --- /dev/null +++ b/filter/image-tiff.c @@ -0,0 +1,1620 @@ +/* + * "$Id$" + * + * TIFF file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageReadTIFF() - Read a TIFF image file. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + +#ifdef HAVE_LIBTIFF +# include /* TIFF image definitions */ +# include + + +/* + * 'ImageReadTIFF()' - Read a TIFF image file. + */ + +int /* O - Read status */ +ImageReadTIFF(image_t *img, /* IO - Image */ + FILE *fp, /* I - Image file */ + int primary, /* I - Primary choice for colorspace */ + int secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + TIFF *tif; /* TIFF file */ + uint32 width, height; /* Size of image */ + uint16 photometric, /* Colorspace */ + orientation, /* Orientation */ + resunit, /* Units for resolution */ + samples, /* Number of samples/pixel */ + bits, /* Number of bits/pixel */ + inkset; /* Ink set for color separations */ + float xres, /* Horizontal resolution */ + yres; /* Vertical resolution */ + uint16 *redcmap, /* Red colormap information */ + *greencmap, /* Green colormap information */ + *bluecmap; /* Blue colormap information */ + int c, /* Color index */ + num_colors, /* Number of colors */ + bpp, /* Bytes per pixel */ + x, y, /* Current x & y */ + xstart, ystart, /* Starting x & y */ + xdir, ydir, /* X & y direction */ + xcount, ycount, /* X & Y counters */ + pstep, /* Pixel step (= bpp or -2 * bpp) */ + scanwidth, /* Width of scanline */ + r, g, b, k, /* Red, green, blue, and black values */ + alpha; /* Image includes alpha? */ + ib_t *in, /* Input buffer */ + *out, /* Output buffer */ + *p, /* Pointer into buffer */ + *scanline, /* Scanline buffer */ + *scanptr, /* Pointer into scanline buffer */ + bit, /* Current bit */ + pixel, /* Current pixel */ + zero, /* Zero value (bitmaps) */ + one; /* One value (bitmaps) */ + + + /* + * Open the TIFF file and get the required parameters... + */ + + lseek(fileno(fp), 0, SEEK_SET); /* Work around "feature" in some stdio's */ + + if ((tif = TIFFFdOpen(fileno(fp), "", "r")) == NULL) + { + fclose(fp); + return (-1); + } + + if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width) || + !TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height) || + !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric) || + !TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samples) || + !TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits)) + { + TIFFClose(tif); + fclose(fp); + return (-1); + } + + /* + * Get the image orientation... + */ + + if (!TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) + orientation = 0; + + /* + * Get the image resolution... + */ + + if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) && + TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) && + TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit)) + { + if (resunit == RESUNIT_INCH) + { + img->xppi = xres; + img->yppi = yres; + } + else if (resunit == RESUNIT_CENTIMETER) + { + img->xppi = xres * 2.54; + img->yppi = yres * 2.54; + } + else + { + img->xppi = xres * 0.0254; + img->yppi = yres * 0.0254; + } + } + + /* + * See if the image has an alpha channel... + */ + + if (samples == 2 || (samples == 4 && photometric == PHOTOMETRIC_RGB)) + alpha = 1; + else + alpha = 0; + + /* + * Setup the image size and colorspace... + */ + + img->xsize = width; + img->ysize = height; + if (photometric == PHOTOMETRIC_MINISBLACK || + photometric == PHOTOMETRIC_MINISWHITE) + img->colorspace = secondary; + else + img->colorspace = primary; + + bpp = ImageGetDepth(img); + + ImageSetMaxTiles(img, 0); + + /* + * Set the X & Y start and direction according to the image orientation... + */ + + switch (orientation) + { + case ORIENTATION_TOPRIGHT : + case ORIENTATION_RIGHTTOP : + xstart = img->xsize - 1; + xdir = -1; + ystart = 0; + ydir = 1; + break; + default : + case ORIENTATION_TOPLEFT : + case ORIENTATION_LEFTTOP : + xstart = 0; + xdir = 1; + ystart = 0; + ydir = 1; + break; + case ORIENTATION_BOTLEFT : + case ORIENTATION_LEFTBOT : + xstart = 0; + xdir = 1; + ystart = img->ysize - 1; + ydir = -1; + break; + case ORIENTATION_BOTRIGHT : + case ORIENTATION_RIGHTBOT : + xstart = img->xsize - 1; + xdir = -1; + ystart = img->ysize - 1; + ydir = -1; + break; + } + + /* + * Allocate a scanline buffer... + */ + + scanwidth = TIFFScanlineSize(tif); + scanline = _TIFFmalloc(scanwidth); + + /* + * Allocate input and output buffers... + */ + + if (orientation < ORIENTATION_LEFTTOP) + { + if (samples > 1 || photometric == PHOTOMETRIC_PALETTE) + pstep = xdir * 3; + else + pstep = xdir; + + in = malloc(img->xsize * 3 + 3); + out = malloc(img->xsize * bpp); + } + else + { + if (samples > 1 || photometric == PHOTOMETRIC_PALETTE) + pstep = ydir * 3; + else + pstep = ydir; + + in = malloc(img->ysize * 3 + 3); + out = malloc(img->ysize * bpp); + } + + /* + * Read the image. This is greatly complicated by the fact that TIFF + * supports literally hundreds of different colorspaces and orientations, + * each which must be handled separately... + */ + + switch (photometric) + { + case PHOTOMETRIC_MINISWHITE : + case PHOTOMETRIC_MINISBLACK : + if (photometric == PHOTOMETRIC_MINISBLACK) + { + zero = 0; + one = 255; + } + else + { + zero = 255; + one = 0; + } + + if (orientation < ORIENTATION_LEFTTOP) + { + /* + * Row major order... + */ + + for (y = ystart, ycount = img->ysize; + ycount > 0; + ycount --, y += ydir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart, bit = 128; + xcount > 0; + xcount --, p += pstep) + { + if (*scanptr & bit) + *p = one; + else + *p = zero; + + if (bit > 1) + bit >>= 1; + else + { + bit = 128; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart, bit = 0xc0; + xcount > 0; + xcount --, p += pstep) + { + pixel = *scanptr & bit; + while (pixel > 3) + pixel >>= 2; + *p = (255 * pixel / 3) ^ zero; + + if (bit > 3) + bit >>= 2; + else + { + bit = 0xc0; + scanptr ++; + } + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart, bit = 0xf0; + xcount > 0; + xcount --, p += pstep) + { + if (bit == 0xf0) + { + *p = (255 * ((*scanptr & 0xf0) >> 4) / 15) ^ zero; + bit = 0x0f; + } + else + { + *p = (255 * (*scanptr & 0x0f) / 15) ^ zero; + bit = 0xf0; + scanptr ++; + } + } + } + else if (xdir < 0 || zero || alpha) + { + TIFFReadScanline(tif, scanline, y, 0); + + if (alpha) + { + if (zero) + { + for (xcount = img->xsize, p = in + xstart, scanptr = scanline; + xcount > 0; + xcount --, p += pstep, scanptr += 2) + *p = (scanptr[1] * (255 - scanptr[0]) + + (255 - scanptr[1]) * 255) / 255; + } + else + { + for (xcount = img->xsize, p = in + xstart, scanptr = scanline; + xcount > 0; + xcount --, p += pstep, scanptr += 2) + *p = (scanptr[1] * scanptr[0] + + (255 - scanptr[1]) * 255) / 255; + } + } + else + { + if (zero) + { + for (xcount = img->xsize, p = in + xstart, scanptr = scanline; + xcount > 0; + xcount --, p += pstep, scanptr ++) + *p = 255 - *scanptr; + } + else + { + for (xcount = img->xsize, p = in + xstart, scanptr = scanline; + xcount > 0; + xcount --, p += pstep, scanptr ++) + *p = *scanptr; + } + } + } + else + TIFFReadScanline(tif, in, y, 0); + + if (img->colorspace == IMAGE_WHITE) + { + if (lut) + ImageLut(in, img->xsize, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_RGB : + ImageWhiteToRGB(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageWhiteToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageWhiteToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + } + else + { + /* + * Column major order... + */ + + for (x = xstart, xcount = img->xsize; + xcount > 0; + xcount --, x += xdir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + ystart, bit = 128; + ycount > 0; + ycount --, p += ydir) + { + if (*scanptr & bit) + *p = one; + else + *p = zero; + + if (bit > 1) + bit >>= 1; + else + { + bit = 128; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + ystart, bit = 0xc0; + ycount > 0; + ycount --, p += ydir) + { + pixel = *scanptr & 0xc0; + while (pixel > 3) + pixel >>= 2; + + *p = (255 * pixel / 3) ^ zero; + + if (bit > 3) + bit >>= 2; + else + { + bit = 0xc0; + scanptr ++; + } + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + ystart, bit = 0xf0; + ycount > 0; + ycount --, p += ydir) + { + if (bit == 0xf0) + { + *p = (255 * ((*scanptr & 0xf0) >> 4) / 15) ^ zero; + bit = 0x0f; + } + else + { + *p = (255 * (*scanptr & 0x0f) / 15) ^ zero; + bit = 0xf0; + scanptr ++; + } + } + } + else if (ydir < 0 || zero || alpha) + { + TIFFReadScanline(tif, scanline, x, 0); + + if (alpha) + { + if (zero) + { + for (ycount = img->ysize, p = in + ystart, scanptr = scanline; + ycount > 0; + ycount --, p += ydir, scanptr += 2) + *p = (scanptr[1] * (255 - scanptr[0]) + + (255 - scanptr[1]) * 255) / 255; + } + else + { + for (ycount = img->ysize, p = in + ystart, scanptr = scanline; + ycount > 0; + ycount --, p += ydir, scanptr += 2) + *p = (scanptr[1] * scanptr[0] + + (255 - scanptr[1]) * 255) / 255; + } + } + else + { + if (zero) + { + for (ycount = img->ysize, p = in + ystart, scanptr = scanline; + ycount > 0; + ycount --, p += ydir, scanptr ++) + *p = 255 - *scanptr; + } + else + { + for (ycount = img->ysize, p = in + ystart, scanptr = scanline; + ycount > 0; + ycount --, p += ydir, scanptr ++) + *p = *scanptr; + } + } + } + else + TIFFReadScanline(tif, in, x, 0); + + if (img->colorspace == IMAGE_WHITE) + { + if (lut) + ImageLut(in, img->ysize, lut); + + ImagePutCol(img, x, 0, img->ysize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_RGB : + ImageWhiteToRGB(in, out, img->ysize); + break; + case IMAGE_BLACK : + ImageWhiteToBlack(in, out, img->ysize); + break; + case IMAGE_CMY : + ImageWhiteToCMY(in, out, img->ysize); + break; + case IMAGE_CMYK : + ImageWhiteToCMYK(in, out, img->ysize); + break; + } + + if (lut) + ImageLut(out, img->ysize * bpp, lut); + + ImagePutCol(img, x, 0, img->ysize, out); + } + } + } + break; + + case PHOTOMETRIC_PALETTE : + if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &redcmap, &greencmap, &bluecmap)) + { + fclose(fp); + return (-1); + } + + num_colors = 1 << bits; + + for (c = 0; c < num_colors; c ++) + { + redcmap[c] >>= 8; + greencmap[c] >>= 8; + bluecmap[c] >>= 8; + } + + if (orientation < ORIENTATION_LEFTTOP) + { + /* + * Row major order... + */ + + for (y = ystart, ycount = img->ysize; + ycount > 0; + ycount --, y += ydir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, + p = in + xstart * 3, bit = 128; + xcount > 0; + xcount --, p += pstep) + { + if (*scanptr & bit) + { + p[0] = redcmap[1]; + p[1] = greencmap[1]; + p[2] = bluecmap[1]; + } + else + { + p[0] = redcmap[0]; + p[1] = greencmap[0]; + p[2] = bluecmap[0]; + } + + if (bit > 1) + bit >>= 1; + else + { + bit = 128; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, + p = in + xstart * 3, bit = 0xc0; + xcount > 0; + xcount --, p += pstep) + { + pixel = *scanptr & bit; + while (pixel > 3) + pixel >>= 2; + + p[0] = redcmap[pixel]; + p[1] = greencmap[pixel]; + p[2] = bluecmap[pixel]; + + if (bit > 3) + bit >>= 2; + else + { + bit = 0xc0; + scanptr ++; + } + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, + p = in + 3 * xstart, bit = 0xf0; + xcount > 0; + xcount --, p += pstep) + { + if (bit == 0xf0) + { + pixel = (*scanptr & 0xf0) >> 4; + p[0] = redcmap[pixel]; + p[1] = greencmap[pixel]; + p[2] = bluecmap[pixel]; + bit = 0x0f; + } + else + { + pixel = *scanptr++ & 0x0f; + p[0] = redcmap[pixel]; + p[1] = greencmap[pixel]; + p[2] = bluecmap[pixel]; + bit = 0xf0; + } + } + } + else + { + TIFFReadScanline(tif, scanline, y, 0); + + for (xcount = img->xsize, p = in + 3 * xstart, scanptr = scanline; + xcount > 0; + xcount --, p += pstep) + { + p[0] = redcmap[*scanptr]; + p[1] = greencmap[*scanptr]; + p[2] = bluecmap[*scanptr++]; + } + } + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(in, img->xsize * 3, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + } + else + { + /* + * Column major order... + */ + + for (x = xstart, xcount = img->xsize; + xcount > 0; + xcount --, x += xdir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, + p = in + 3 * ystart, bit = 128; + ycount > 0; + ycount --, p += ydir) + { + if (*scanptr & bit) + { + p[0] = redcmap[1]; + p[1] = greencmap[1]; + p[2] = bluecmap[1]; + } + else + { + p[0] = redcmap[0]; + p[1] = greencmap[0]; + p[2] = bluecmap[0]; + } + + if (bit > 1) + bit >>= 1; + else + { + bit = 128; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, + p = in + 3 * ystart, bit = 0xc0; + ycount > 0; + ycount --, p += ydir) + { + pixel = *scanptr & 0xc0; + while (pixel > 3) + pixel >>= 2; + + p[0] = redcmap[pixel]; + p[1] = greencmap[pixel]; + p[2] = bluecmap[pixel]; + + if (bit > 3) + bit >>= 2; + else + { + bit = 0xc0; + scanptr ++; + } + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, + p = in + 3 * ystart, bit = 0xf0; + ycount > 0; + ycount --, p += ydir) + { + if (bit == 0xf0) + { + pixel = (*scanptr & 0xf0) >> 4; + p[0] = redcmap[pixel]; + p[1] = greencmap[pixel]; + p[2] = bluecmap[pixel]; + bit = 0x0f; + } + else + { + pixel = *scanptr++ & 0x0f; + p[0] = redcmap[pixel]; + p[1] = greencmap[pixel]; + p[2] = bluecmap[pixel]; + bit = 0xf0; + } + } + } + else + { + TIFFReadScanline(tif, scanline, x, 0); + + for (ycount = img->ysize, p = in + 3 * ystart, scanptr = scanline; + ycount > 0; + ycount --, p += ydir) + { + p[0] = redcmap[*scanptr]; + p[1] = greencmap[*scanptr]; + p[2] = bluecmap[*scanptr++]; + } + } + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(in, img->ysize * 3, lut); + + ImagePutCol(img, x, 0, img->ysize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->ysize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->ysize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->ysize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->ysize); + break; + } + + if (lut) + ImageLut(out, img->ysize * bpp, lut); + + ImagePutCol(img, x, 0, img->ysize, out); + } + } + } + break; + + case PHOTOMETRIC_RGB : + if (orientation < ORIENTATION_LEFTTOP) + { + /* + * Row major order... + */ + + for (y = ystart, ycount = img->ysize; + ycount > 0; + ycount --, y += ydir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3, bit = 0xf0; + xcount > 0; + xcount --, p += pstep) + { + if (*scanptr & bit & 0x88) + p[0] = 255; + else + p[0] = 0; + + if (*scanptr & bit & 0x44) + p[1] = 255; + else + p[1] = 0; + + if (*scanptr & bit & 0x22) + p[2] = 255; + else + p[2] = 0; + + if (bit == 0xf0) + bit = 0x0f; + else + { + bit = 0xf0; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3; + xcount > 0; + xcount --, p += pstep, scanptr ++) + { + pixel = *scanptr >> 2; + p[0] = 255 * (pixel & 3) / 3; + pixel >>= 2; + p[1] = 255 * (pixel & 3) / 3; + pixel >>= 2; + p[2] = 255 * (pixel & 3) / 3; + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3; + xcount > 0; + xcount -= 2, p += 2 * pstep, scanptr += 3) + { + pixel = scanptr[0]; + p[1] = 255 * (pixel & 15) / 15; + pixel >>= 4; + p[0] = 255 * (pixel & 15) / 15; + pixel = scanptr[1]; + p[2] = 255 * ((pixel >> 4) & 15) / 15; + + if (xcount > 1) + { + p[pstep + 0] = 255 * (pixel & 15) / 15; + pixel = scanptr[2]; + p[pstep + 2] = 255 * (pixel & 15) / 15; + pixel >>= 4; + p[pstep + 1] = 255 * (pixel & 15) / 15; + } + } + } + else if (xdir < 0 || alpha) + { + TIFFReadScanline(tif, scanline, y, 0); + + if (alpha) + { + for (xcount = img->xsize, p = in + xstart * 3, scanptr = scanline; + xcount > 0; + xcount --, p += pstep, scanptr += 4) + { + p[0] = (scanptr[0] * scanptr[3] + 255 * (255 - scanptr[3])) / 255; + p[1] = (scanptr[1] * scanptr[3] + 255 * (255 - scanptr[3])) / 255; + p[2] = (scanptr[2] * scanptr[3] + 255 * (255 - scanptr[3])) / 255; + } + } + else + { + for (xcount = img->xsize, p = in + xstart * 3, scanptr = scanline; + xcount > 0; + xcount --, p += pstep, scanptr += 3) + { + p[0] = scanptr[0]; + p[1] = scanptr[1]; + p[2] = scanptr[2]; + } + } + } + else + TIFFReadScanline(tif, in, y, 0); + + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(in, img->xsize * 3, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * bpp, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + } + else + { + /* + * Column major order... + */ + + for (x = xstart, xcount = img->xsize; + xcount > 0; + xcount --, x += xdir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + ystart * 3, bit = 0xf0; + ycount > 0; + ycount --, p += pstep) + { + if (*scanptr & bit & 0x88) + p[0] = one; + else + p[0] = zero; + + if (*scanptr & bit & 0x44) + p[1] = one; + else + p[1] = zero; + + if (*scanptr & bit & 0x22) + p[2] = one; + else + p[2] = zero; + + if (bit == 0xf0) + bit = 0x0f; + else + { + bit = 0xf0; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + ystart * 3; + ycount > 0; + ycount --, p += pstep, scanptr ++) + { + pixel = *scanptr >> 2; + p[0] = 255 * (pixel & 3) / 3; + pixel >>= 2; + p[1] = 255 * (pixel & 3) / 3; + pixel >>= 2; + p[2] = 255 * (pixel & 3) / 3; + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + ystart * 3; + ycount > 0; + ycount -= 2, p += 2 * pstep, scanptr += 3) + { + pixel = scanptr[0]; + p[1] = 255 * (pixel & 15) / 15; + pixel >>= 4; + p[0] = 255 * (pixel & 15) / 15; + pixel = scanptr[1]; + p[2] = 255 * ((pixel >> 4) & 15) / 15; + + if (ycount > 1) + { + p[pstep + 0] = 255 * (pixel & 15) / 15; + pixel = scanptr[2]; + p[pstep + 2] = 255 * (pixel & 15) / 15; + pixel >>= 4; + p[pstep + 1] = 255 * (pixel & 15) / 15; + } + } + } + else if (ydir < 0 || alpha) + { + TIFFReadScanline(tif, scanline, x, 0); + + if (alpha) + { + for (ycount = img->ysize, p = in + ystart * 3, scanptr = scanline; + ycount > 0; + ycount --, p += pstep, scanptr += 4) + { + p[0] = (scanptr[0] * scanptr[3] + 255 * (255 - scanptr[3])) / 255; + p[1] = (scanptr[1] * scanptr[3] + 255 * (255 - scanptr[3])) / 255; + p[2] = (scanptr[2] * scanptr[3] + 255 * (255 - scanptr[3])) / 255; + } + } + else + { + for (ycount = img->ysize, p = in + ystart * 3, scanptr = scanline; + ycount > 0; + ycount --, p += pstep, scanptr += 3) + { + p[0] = scanptr[0]; + p[1] = scanptr[1]; + p[2] = scanptr[2]; + } + } + } + else + TIFFReadScanline(tif, in, x, 0); + + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->ysize, saturation, hue); + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(in, img->ysize * 3, lut); + + ImagePutCol(img, x, 0, img->ysize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->ysize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->ysize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->ysize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->ysize); + break; + } + + if (lut) + ImageLut(out, img->ysize * bpp, lut); + + ImagePutCol(img, x, 0, img->ysize, out); + } + } + } + break; + + case PHOTOMETRIC_SEPARATED : + TIFFGetField(tif, TIFFTAG_INKSET, &inkset); + + if (inkset == INKSET_CMYK) + { + if (orientation < ORIENTATION_LEFTTOP) + { + /* + * Row major order... + */ + + for (y = ystart, ycount = img->ysize; + ycount > 0; + ycount --, y += ydir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3, bit = 0xf0; + xcount > 0; + xcount --, p += pstep) + { + if (*scanptr & bit & 0x11) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + if (*scanptr & bit & 0x88) + p[0] = 0; + else + p[0] = 255; + + if (*scanptr & bit & 0x44) + p[1] = 0; + else + p[1] = 255; + + if (*scanptr & bit & 0x22) + p[2] = 0; + else + p[2] = 255; + } + + if (bit == 0xf0) + bit = 0x0f; + else + { + bit = 0xf0; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3; + xcount > 0; + xcount --, p += pstep, scanptr ++) + { + pixel = *scanptr; + k = 255 * (pixel & 3) / 3; + if (k == 255) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + pixel >>= 2; + b = 255 - 255 * (pixel & 3) / 3 - k; + if (b < 0) + p[2] = 0; + else if (b < 256) + p[2] = b; + else + p[2] = 255; + + pixel >>= 2; + g = 255 - 255 * (pixel & 3) / 3 - k; + if (g < 0) + p[1] = 0; + else if (g < 256) + p[1] = g; + else + p[1] = 255; + + pixel >>= 2; + r = 255 - 255 * (pixel & 3) / 3 - k; + if (r < 0) + p[0] = 0; + else if (r < 256) + p[0] = r; + else + p[0] = 255; + } + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, y, 0); + for (xcount = img->xsize, scanptr = scanline, p = in + xstart * 3; + xcount > 0; + xcount --, p += pstep, scanptr += 2) + { + pixel = scanptr[1]; + k = 255 * (pixel & 15) / 15; + if (k == 255) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + pixel >>= 4; + b = 255 - 255 * (pixel & 15) / 15 - k; + if (b < 0) + p[2] = 0; + else if (b < 256) + p[2] = b; + else + p[2] = 255; + + pixel = scanptr[0]; + g = 255 - 255 * (pixel & 15) / 15 - k; + if (g < 0) + p[1] = 0; + else if (g < 256) + p[1] = g; + else + p[1] = 255; + + pixel >>= 4; + r = 255 - 255 * (pixel & 15) / 15 - k; + if (r < 0) + p[0] = 0; + else if (r < 256) + p[0] = r; + else + p[0] = 255; + } + } + } + else + { + TIFFReadScanline(tif, scanline, y, 0); + + for (xcount = img->xsize, p = in + xstart * 3, scanptr = scanline; + xcount > 0; + xcount --, p += pstep, scanptr += 4) + { + k = scanptr[3]; + if (k == 255) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + r = 255 - scanptr[0] - k; + if (r < 0) + p[0] = 0; + else if (r < 256) + p[0] = r; + else + p[0] = 255; + + g = 255 - scanptr[1] - k; + if (g < 0) + p[1] = 0; + else if (g < 256) + p[1] = g; + else + p[1] = 255; + + b = 255 - scanptr[2] - k; + if (b < 0) + p[2] = 0; + else if (b < 256) + p[2] = b; + else + p[2] = 255; + } + } + } + + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->xsize, saturation, hue); + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(in, img->xsize * 3, lut); + + ImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->xsize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->xsize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->xsize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + ImageLut(out, img->xsize * 3, lut); + + ImagePutRow(img, 0, y, img->xsize, out); + } + } + } + else + { + /* + * Column major order... + */ + + for (x = xstart, xcount = img->xsize; + xcount > 0; + xcount --, x += xdir) + { + if (bits == 1) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + xstart * 3, bit = 0xf0; + ycount > 0; + ycount --, p += pstep) + { + if (*scanptr & bit & 0x11) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + if (*scanptr & bit & 0x88) + p[0] = 0; + else + p[0] = 255; + + if (*scanptr & bit & 0x44) + p[1] = 0; + else + p[1] = 255; + + if (*scanptr & bit & 0x22) + p[2] = 0; + else + p[2] = 255; + } + + if (bit == 0xf0) + bit = 0x0f; + else + { + bit = 0xf0; + scanptr ++; + } + } + } + else if (bits == 2) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + xstart * 3; + ycount > 0; + ycount --, p += pstep, scanptr ++) + { + pixel = *scanptr; + k = 255 * (pixel & 3) / 3; + if (k == 255) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + pixel >>= 2; + b = 255 - 255 * (pixel & 3) / 3 - k; + if (b < 0) + p[2] = 0; + else if (b < 256) + p[2] = b; + else + p[2] = 255; + + pixel >>= 2; + g = 255 - 255 * (pixel & 3) / 3 - k; + if (g < 0) + p[1] = 0; + else if (g < 256) + p[1] = g; + else + p[1] = 255; + + pixel >>= 2; + r = 255 - 255 * (pixel & 3) / 3 - k; + if (r < 0) + p[0] = 0; + else if (r < 256) + p[0] = r; + else + p[0] = 255; + } + } + } + else if (bits == 4) + { + TIFFReadScanline(tif, scanline, x, 0); + for (ycount = img->ysize, scanptr = scanline, p = in + xstart * 3; + ycount > 0; + ycount --, p += pstep, scanptr += 2) + { + pixel = scanptr[1]; + k = 255 * (pixel & 15) / 15; + if (k == 255) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + pixel >>= 4; + b = 255 - 255 * (pixel & 15) / 15 - k; + if (b < 0) + p[2] = 0; + else if (b < 256) + p[2] = b; + else + p[2] = 255; + + pixel = scanptr[0]; + g = 255 - 255 * (pixel & 15) / 15 - k; + if (g < 0) + p[1] = 0; + else if (g < 256) + p[1] = g; + else + p[1] = 255; + + pixel >>= 4; + r = 255 - 255 * (pixel & 15) / 15 - k; + if (r < 0) + p[0] = 0; + else if (r < 256) + p[0] = r; + else + p[0] = 255; + } + } + } + else + { + TIFFReadScanline(tif, scanline, x, 0); + + for (ycount = img->ysize, p = in + xstart * 3, scanptr = scanline; + ycount > 0; + ycount --, p += pstep, scanptr += 4) + { + k = scanptr[3]; + if (k == 255) + { + p[0] = 0; + p[1] = 0; + p[2] = 0; + } + else + { + r = 255 - scanptr[0] - k; + if (r < 0) + p[0] = 0; + else if (r < 256) + p[0] = r; + else + p[0] = 255; + + g = 255 - scanptr[1] - k; + if (g < 0) + p[1] = 0; + else if (g < 256) + p[1] = g; + else + p[1] = 255; + + b = 255 - scanptr[2] - k; + if (b < 0) + p[2] = 0; + else if (b < 256) + p[2] = b; + else + p[2] = 255; + } + } + } + + if ((saturation != 100 || hue != 0) && bpp > 1) + ImageRGBAdjust(in, img->ysize, saturation, hue); + + if (img->colorspace == IMAGE_RGB) + { + if (lut) + ImageLut(in, img->ysize * 3, lut); + + ImagePutCol(img, x, 0, img->ysize, in); + } + else + { + switch (img->colorspace) + { + case IMAGE_WHITE : + ImageRGBToWhite(in, out, img->ysize); + break; + case IMAGE_BLACK : + ImageRGBToBlack(in, out, img->ysize); + break; + case IMAGE_CMY : + ImageRGBToCMY(in, out, img->ysize); + break; + case IMAGE_CMYK : + ImageRGBToCMYK(in, out, img->ysize); + break; + } + + if (lut) + ImageLut(out, img->ysize * bpp, lut); + + ImagePutCol(img, x, 0, img->ysize, out); + } + } + } + + break; + } + + default : + _TIFFfree(scanline); + free(in); + free(out); + + TIFFClose(tif); + return (-1); + } + + /* + * Free temporary buffers, close the TIFF file, and return. + */ + + _TIFFfree(scanline); + free(in); + free(out); + + TIFFClose(tif); + return (0); +} + + +#endif /* HAVE_LIBTIFF */ + + +/* + * End of "$Id$". + */ diff --git a/filter/image-zoom.c b/filter/image-zoom.c new file mode 100644 index 0000000000..455dd52263 --- /dev/null +++ b/filter/image-zoom.c @@ -0,0 +1,310 @@ +/* + * "$Id$" + * + * Image zoom routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ImageZoomAlloc() - Allocate a pixel zoom record... + * ImageZoomFill() - Fill a zoom record with image data utilizing bilinear + * interpolation. + * ImageZoomQFill() - Fill a zoom record quickly using nearest-neighbor + * sampling. + * ImageZoomFree() - Free a zoom record... + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + + +/* + * 'ZoomAlloc()' - Allocate a pixel zoom record... + */ + +izoom_t * +ImageZoomAlloc(image_t *img, /* I - Image to zoom */ + int x0, /* I - Upper-lefthand corner */ + int y0, /* I - ... */ + int x1, /* I - Lower-righthand corner */ + int y1, /* I - ... */ + int xsize, /* I - Final width of image */ + int ysize, /* I - Final height of image */ + int rotated) /* I - Non-zero if image is rotated 90 degs */ +{ + izoom_t *z; /* New zoom record */ + + + if ((z = (izoom_t *)calloc(1, sizeof(izoom_t))) == NULL) + return (NULL); + + z->img = img; + z->row = 0; + z->depth = ImageGetDepth(img); + z->rotated = rotated; + + if (rotated) + { + z->xorig = x1; + z->yorig = y0; + z->width = y1 - y0 + 1; + z->height = x1 - x0 + 1; + z->xsize = xsize; + z->ysize = ysize; + z->xmod = z->width % z->xsize; + z->xstep = z->width / z->xsize; + z->xincr = 1; + z->ymod = z->height % z->ysize; + z->ystep = z->height / z->ysize; + z->yincr = 1; + z->instep = z->xstep * z->depth; + z->inincr = z->xincr * z->depth; + + if (z->width < img->ysize) + z->xmax = z->width; + else + z->xmax = z->width - 1; + + if (z->height < img->xsize) + z->ymax = z->height; + else + z->ymax = z->height - 1; + } + else + { + z->xorig = x0; + z->yorig = y0; + z->width = x1 - x0 + 1; + z->height = y1 - y0 + 1; + z->xsize = xsize; + z->ysize = ysize; + z->xmod = z->width % z->xsize; + z->xstep = z->width / z->xsize; + z->xincr = 1; + z->ymod = z->height % z->ysize; + z->ystep = z->height / z->ysize; + z->yincr = 1; + z->instep = z->xstep * z->depth; + z->inincr = z->xincr * z->depth; + + if (z->width < img->xsize) + z->xmax = z->width; + else + z->xmax = z->width - 1; + + if (z->height < img->ysize) + z->ymax = z->height; + else + z->ymax = z->height - 1; + } + + if ((z->rows[0] = (ib_t *)malloc(z->xsize * z->depth)) == NULL) + { + free(z); + return (NULL); + } + + if ((z->rows[1] = (ib_t *)malloc(z->xsize * z->depth)) == NULL) + { + free(z->rows[0]); + free(z); + return (NULL); + } + + if ((z->in = (ib_t *)malloc(z->width * z->depth)) == NULL) + { + free(z->rows[0]); + free(z->rows[1]); + free(z); + return (NULL); + } + + return (z); +} + + +/* + * 'ImageZoomFill()' - Fill a zoom record with image data utilizing bilinear + * interpolation. + */ + +void +ImageZoomFill(izoom_t *z, /* I - Zoom record to fill */ + int iy) /* I - Zoom image row */ +{ + ib_t *r, /* Row pointer */ + *inptr; /* Pixel pointer */ + int xerr0, /* X error counter */ + xerr1; /* ... */ + int ix, + x, + count, + z_depth, + z_xstep, + z_xincr, + z_instep, + z_inincr, + z_xmax, + z_xmod, + z_xsize; + + + if (iy > z->ymax) + iy = z->ymax; + + z->row ^= 1; + + z_depth = z->depth; + z_xsize = z->xsize; + z_xmax = z->xmax; + z_xmod = z->xmod; + z_xstep = z->xstep; + z_xincr = z->xincr; + z_instep = z->instep; + z_inincr = z->inincr; + + if (z->rotated) + ImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in); + else + ImageGetRow(z->img, z->xorig, z->yorig + iy, z->width, z->in); + + if (z_inincr < 0) + inptr = z->in + (z->width - 1) * z_depth; + else + inptr = z->in; + + for (x = z_xsize, xerr0 = z_xsize, xerr1 = 0, ix = 0, r = z->rows[z->row]; + x > 0; + x --) + { + if (ix < z_xmax) + { + for (count = 0; count < z_depth; count ++) + *r++ = (inptr[count] * xerr0 + inptr[z_depth + count] * xerr1) / z_xsize; + } + else + { + for (count = 0; count < z_depth; count ++) + *r++ = inptr[count]; + } + + ix += z_xstep; + inptr += z_instep; + xerr0 -= z_xmod; + xerr1 += z_xmod; + + if (xerr0 <= 0) + { + xerr0 += z_xsize; + xerr1 -= z_xsize; + ix += z_xincr; + inptr += z_inincr; + } + } +} + + +/* + * 'ImageZoomQFill()' - Fill a zoom record quickly using nearest-neighbor sampling. + */ + +void +ImageZoomQFill(izoom_t *z, /* I - Zoom record to fill */ + int iy) /* I - Zoom image row */ +{ + ib_t *r, /* Row pointer */ + *inptr; /* Pixel pointer */ + int xerr0; /* X error counter */ + int ix, + x, + count, + z_depth, + z_xstep, + z_xincr, + z_instep, + z_inincr, + z_xmod, + z_xsize; + + + if (iy > z->ymax) + iy = z->ymax; + + z->row ^= 1; + + z_depth = z->depth; + z_xsize = z->xsize; + z_xmod = z->xmod; + z_xstep = z->xstep; + z_xincr = z->xincr; + z_instep = z->instep; + z_inincr = z->inincr; + + if (z->rotated) + ImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in); + else + ImageGetRow(z->img, z->xorig, z->yorig + iy, z->width, z->in); + + if (z_inincr < 0) + inptr = z->in + (z->width - 1) * z_depth; + else + inptr = z->in; + + for (x = z_xsize, xerr0 = z_xsize, ix = 0, r = z->rows[z->row]; + x > 0; + x --) + { + for (count = 0; count < z_depth; count ++) + *r++ = inptr[count]; + + ix += z_xstep; + inptr += z_instep; + xerr0 -= z_xmod; + + if (xerr0 <= 0) + { + xerr0 += z_xsize; + ix += z_xincr; + inptr += z_inincr; + } + } +} + + +/* + * 'ImageZoomFree()' - Free a zoom record... + */ + +void +ImageZoomFree(izoom_t *z) /* I - Zoom record to free */ +{ + free(z->rows[0]); + free(z->rows[1]); + free(z->in); + free(z); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image.c b/filter/image.c new file mode 100644 index 0000000000..d7755bdd80 --- /dev/null +++ b/filter/image.c @@ -0,0 +1,759 @@ +/* + * "$Id$" + * + * Base image support for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * 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. + * ImagePutRow() - Put a row of pixels to an image. + * get_tile() - Get a cached tile. + * flush_tile() - Flush the least-recently-used tile in the cache. + */ + +/* + * Include necessary headers... + */ + +#include "image.h" +#include +#include +#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... + */ + +static ib_t *get_tile(image_t *img, int x, int y); +static void flush_tile(image_t *img); + + +/* + * 'ImageOpen()' - Open an image file and read it into memory. + */ + +image_t * /* O - New image */ +ImageOpen(char *filename, /* I - Filename of image */ + int primary, /* I - Primary colorspace needed */ + int secondary, /* I - Secondary colorspace if primary no good */ + int saturation,/* I - Color saturation level */ + int hue, /* I - Color hue adjustment */ + const ib_t *lut) /* I - RGB gamma/brightness LUT */ +{ + FILE *fp; /* File pointer */ + unsigned char header[16], /* First 16 bytes of file */ + header2[16]; /* Bytes 2048-2064 (PhotoCD) */ + image_t *img; /* New image buffer */ + int status; /* Status of load... */ + + + /* + * Range check... + */ + + if (filename == NULL) + return (NULL); + + /* + * Figure out the file type... + */ + + if ((fp = fopen(filename, "r")) == NULL) + return (NULL); + + if (fread(header, 1, sizeof(header), fp) == 0) + { + fclose(fp); + return (NULL); + } + + fseek(fp, 2048, SEEK_SET); + memset(header2, 0, sizeof(header2)); + fread(header2, 1, sizeof(header2), fp); + fseek(fp, 0, SEEK_SET); + + /* + * Allocate memory... + */ + + img = calloc(sizeof(image_t), 1); + + if (img == NULL) + { + fclose(fp); + return (NULL); + } + + /* + * Load the image as appropriate... + */ + + img->max_ics = TILE_MINIMUM; + img->xppi = 128; + img->yppi = 128; + + if (memcmp(header, "GIF87a", 6) == 0 || + memcmp(header, "GIF89a", 6) == 0) + status = ImageReadGIF(img, fp, primary, secondary, saturation, hue, lut); + else if (header[0] == 0x01 && header[1] == 0xda) + status = ImageReadSGI(img, fp, primary, secondary, saturation, hue, lut); + else if (header[0] == 0x59 && header[1] == 0xa6 && + header[2] == 0x6a && header[3] == 0x95) + status = ImageReadSunRaster(img, fp, primary, secondary, saturation, hue, lut); + else if (header[0] == 'P' && header[1] >= '1' && header[1] <= '6') + status = ImageReadPNM(img, fp, primary, secondary, saturation, hue, lut); + else if (memcmp(header2, "PCD_IPI", 7) == 0) + status = ImageReadPhotoCD(img, fp, primary, secondary, saturation, hue, lut); +#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) + else if (memcmp(header, "\211PNG", 4) == 0) + status = ImageReadPNG(img, fp, primary, secondary, saturation, hue, lut); +#endif /* HAVE_LIBPNG && HAVE_LIBZ */ +#ifdef HAVE_LIBJPEG + else if (memcmp(header + 6, "JFIF", 4) == 0) + status = ImageReadJPEG(img, fp, primary, secondary, saturation, hue, lut); +#endif /* HAVE_LIBJPEG */ +#ifdef HAVE_LIBTIFF + else if (memcmp(header, "MM", 2) == 0 || + memcmp(header, "II", 2) == 0) + status = ImageReadTIFF(img, fp, primary, secondary, saturation, hue, lut); +#endif /* HAVE_LIBTIFF */ + else + { + fclose(fp); + status = -1; + } + + if (status) + { + free(img); + return (NULL); + } + else + return (img); +} + + +/* + * 'ImageClose()' - Close an image file. + */ + +void +ImageClose(image_t *img) /* I - Image to close */ +{ + ic_t *current, /* Current cached tile */ + *next; /* Next cached tile */ + + + /* + * Wipe the tile cache file (if any)... + */ + + if (img->cachefile != NULL) + { + fprintf(stderr, "DEBUG: Closing and removing swap file \"%s\"...\n", + img->cachename); + + fclose(img->cachefile); + unlink(img->cachename); + } + + /* + * Free the image cache... + */ + + fputs("DEBUG: Freeing memory...\n", stderr); + + for (current = img->first; current != NULL; current = next) + { + fprintf(stderr, "DEBUG: Freeing cache (%08lx, next = %08lx)...\n", + current, next); + + next = current->next; + free(current); + } + + /* + * Free the rest of memory... + */ + + if (img->tiles != NULL) + { + fprintf(stderr, "DEBUG: Freeing tiles (%08lx)...\n", img->tiles[0]); + + free(img->tiles[0]); + + fprintf(stderr, "DEBUG: Freeing tile pointers (%08lx)...\n", img->tiles); + + free(img->tiles); + } + + free(img); +} + + +/* + * 'ImageSetMaxTiles()' - Set the maximum number of tiles to cache. + * + * If the "max_tiles" argument is 0 then the maximum number of tiles is + * computed from the image size or the RIP_CACHE environment variable. + */ + +void +ImageSetMaxTiles(image_t *img, /* I - Image to set */ + int max_tiles) /* I - Number of tiles to cache */ +{ + int cache_size, /* Size of tile cache in bytes */ + min_tiles, /* Minimum number of tiles to cache */ + max_size; /* Maximum cache size in bytes */ + char *cache_env, /* Cache size environment variable */ + cache_units[255]; /* Cache size units */ + + + min_tiles = max(TILE_MINIMUM, + 1 + max((img->xsize + TILE_SIZE - 1) / TILE_SIZE, + (img->ysize + TILE_SIZE - 1) / TILE_SIZE)); + + if (max_tiles == 0) + max_tiles = ((img->xsize + TILE_SIZE - 1) / TILE_SIZE) * + ((img->ysize + TILE_SIZE - 1) / TILE_SIZE); + + cache_size = max_tiles * TILE_SIZE * TILE_SIZE * ImageGetDepth(img); + + if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL) + { + switch (sscanf(cache_env, "%d%s", &max_size, cache_units)) + { + case 0 : + max_size = 32 * 1024 * 1024; + break; + case 1 : + max_size *= 4 * TILE_SIZE * TILE_SIZE; + break; + case 2 : + if (tolower(cache_units[0]) == 'g') + max_size *= 1024 * 1024 * 1024; + else if (tolower(cache_units[0]) == 'm') + max_size *= 1024 * 1024; + else if (tolower(cache_units[0]) == 'k') + max_size *= 1024; + else if (tolower(cache_units[0]) == 't') + max_size *= 4 * TILE_SIZE * TILE_SIZE; + break; + } + } + else + max_size = 32 * 1024 * 1024; + + if (cache_size > max_size) + max_tiles = max_size / TILE_SIZE / TILE_SIZE / ImageGetDepth(img); + + if (max_tiles < min_tiles) + max_tiles = min_tiles; + + img->max_ics = max_tiles; + + fprintf(stderr, "DEBUG: max_ics=%d...\n", img->max_ics); +} + + +/* + * '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. + */ + +int /* O - -1 on error, 0 on success */ +ImageGetCol(image_t *img, /* I - Image */ + int x, /* I - Column */ + int y, /* I - Start row */ + int height, /* I - Column height */ + ib_t *pixels) /* O - Pixel data */ +{ + int bpp, /* Bytes per pixel */ + twidth, /* Tile width */ + count; /* Number of pixels to get */ + const ib_t *ib; /* Pointer into tile */ + + + if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize) + return (-1); + + if (y < 0) + { + height += y; + y = 0; + } + + if ((y + height) > img->ysize) + height = img->ysize - y; + + if (height < 1) + return (-1); + + bpp = ImageGetDepth(img); + twidth = bpp * (TILE_SIZE - 1); + + while (height > 0) + { + ib = get_tile(img, x, y); + + if (ib == NULL) + return (-1); + + count = TILE_SIZE - (y & (TILE_SIZE - 1)); + if (count > height) + count = height; + + y += count; + height -= count; + + for (; count > 0; count --, ib += twidth) + switch (bpp) + { + case 4 : + *pixels++ = *ib++; + case 3 : + *pixels++ = *ib++; + *pixels++ = *ib++; + case 1 : + *pixels++ = *ib++; + break; + } + } + + return (0); +} + + +/* + * 'ImageGetRow()' - Get a row of pixels from an image. + */ + +int /* O - -1 on error, 0 on success */ +ImageGetRow(image_t *img, /* I - Image */ + int x, /* I - Start column */ + int y, /* I - Row */ + int width, /* I - Width of row */ + ib_t *pixels) /* O - Pixel data */ +{ + int bpp, /* Bytes per pixel */ + count; /* Number of pixels to get */ + const ib_t *ib; /* Pointer to pixels */ + + + if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize) + return (-1); + + if (x < 0) + { + width += x; + x = 0; + } + + if ((x + width) > img->xsize) + width = img->xsize - x; + + if (width < 1) + return (-1); + + bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace; + + while (width > 0) + { + ib = get_tile(img, x, y); + + if (ib == NULL) + return (-1); + + count = TILE_SIZE - (x & (TILE_SIZE - 1)); + if (count > width) + count = width; + memcpy(pixels, ib, count * bpp); + pixels += count * bpp; + x += count; + width -= count; + } + + return (0); +} + + +/* + * 'ImagePutCol()' - Put a column of pixels to an image. + */ + +int /* O - -1 on error, 0 on success */ +ImagePutCol(image_t *img, /* I - Image */ + int x, /* I - Column */ + int y, /* I - Start row */ + int height, /* I - Column height */ + const ib_t *pixels) /* I - Pixels to put */ +{ + int bpp, /* Bytes per pixel */ + twidth, /* Width of tile */ + count; /* Number of pixels to put */ + int tilex, /* Column within tile */ + tiley; /* Row within tile */ + ib_t *ib; /* Pointer to pixels in tile */ + + + if (img == NULL || x < 0 || x >= img->xsize || y >= img->ysize) + return (-1); + + if (y < 0) + { + height += y; + y = 0; + } + + if ((y + height) > img->ysize) + height = img->ysize - y; + + if (height < 1) + return (-1); + + bpp = ImageGetDepth(img); + twidth = bpp * (TILE_SIZE - 1); + tilex = x / TILE_SIZE; + tiley = y / TILE_SIZE; + + while (height > 0) + { + ib = get_tile(img, x, y); + + if (ib == NULL) + return (-1); + + img->tiles[tiley][tilex].dirty = 1; + tiley ++; + + count = TILE_SIZE - (y & (TILE_SIZE - 1)); + if (count > height) + count = height; + + y += count; + height -= count; + + for (; count > 0; count --, ib += twidth) + switch (bpp) + { + case 4 : + *ib++ = *pixels++; + case 3 : + *ib++ = *pixels++; + *ib++ = *pixels++; + case 1 : + *ib++ = *pixels++; + break; + } + } + + return (0); +} + + +/* + * 'ImagePutRow()' - Put a row of pixels to an image. + */ + +int /* O - -1 on error, 0 on success */ +ImagePutRow(image_t *img, /* I - Image */ + int x, /* I - Start column */ + int y, /* I - Row */ + int width, /* I - Row width */ + const ib_t *pixels) /* I - Pixel data */ +{ + int bpp, /* Bytes per pixel */ + count; /* Number of pixels to put */ + int tilex, /* Column within tile */ + tiley; /* Row within tile */ + ib_t *ib; /* Pointer to pixels in tile */ + + + if (img == NULL || y < 0 || y >= img->ysize || x >= img->xsize) + return (-1); + + if (x < 0) + { + width += x; + x = 0; + } + + if ((x + width) > img->xsize) + width = img->xsize - x; + + if (width < 1) + return (-1); + + bpp = img->colorspace < 0 ? -img->colorspace : img->colorspace; + tilex = x / TILE_SIZE; + tiley = y / TILE_SIZE; + + while (width > 0) + { + ib = get_tile(img, x, y); + + if (ib == NULL) + return (-1); + + img->tiles[tiley][tilex].dirty = 1; + + count = TILE_SIZE - (x & (TILE_SIZE - 1)); + if (count > width) + count = width; + memcpy(ib, pixels, count * bpp); + pixels += count * bpp; + x += count; + width -= count; + tilex ++; + } + + return (0); +} + + +/* + * 'get_tile()' - Get a cached tile. + */ + +static ib_t * /* O - Pointer to tile or NULL */ +get_tile(image_t *img, /* I - Image */ + int x, /* I - Column in image */ + int y) /* I - Row in image */ +{ + int bpp, /* Bytes per pixel */ + tilex, /* Column within tile */ + tiley, /* Row within tile */ + xtiles, /* Number of tiles horizontally */ + ytiles; /* Number of tiles vertically */ + ic_t *ic; /* Cache pointer */ + itile_t *tile; /* Tile pointer */ + + + if (x >= img->xsize || y >= img->ysize) + { + fprintf(stderr, "ERROR: Internal image RIP error - %d,%d is outside of %dx%d\n", + x, y, img->xsize, img->ysize); + return (NULL); + } + + if (img->tiles == NULL) + { + xtiles = (img->xsize + TILE_SIZE - 1) / TILE_SIZE; + ytiles = (img->ysize + TILE_SIZE - 1) / TILE_SIZE; + + fprintf(stderr, "DEBUG: Creating tile array (%dx%d)\n", xtiles, ytiles); + + img->tiles = calloc(sizeof(itile_t *), ytiles); + tile = calloc(sizeof(itile_t), xtiles * ytiles); + + for (tiley = 0; tiley < ytiles; tiley ++) + { + img->tiles[tiley] = tile; + for (tilex = xtiles; tilex > 0; tilex --, tile ++) + tile->pos = -1; + } + } + + bpp = ImageGetDepth(img); + tilex = x / TILE_SIZE; + tiley = y / TILE_SIZE; + x &= (TILE_SIZE - 1); + y &= (TILE_SIZE - 1); + + tile = img->tiles[tiley] + tilex; + + if ((ic = tile->ic) == NULL) + { + if (img->num_ics < img->max_ics) + { + ic = calloc(sizeof(ic_t) + bpp * TILE_SIZE * TILE_SIZE, 1); + ic->pixels = ((ib_t *)ic) + sizeof(ic_t); + + img->num_ics ++; + + fprintf(stderr, "DEBUG: Allocated cache tile %d (%08lx)...\n", + img->num_ics, ic); + } + else + { + fprintf(stderr, "DEBUG: Flushing old cache tile (%08lx)...\n", + img->first); + + flush_tile(img); + ic = img->first; + } + + ic->tile = tile; + tile->ic = ic; + + if (tile->pos >= 0) + { + fprintf(stderr, "DEBUG: Loading cache tile from file position %d...\n", + tile->pos); + + if (ftell(img->cachefile) != tile->pos) + if (fseek(img->cachefile, tile->pos, SEEK_SET)) + perror("get_tile:"); + + fread(ic->pixels, bpp, TILE_SIZE * TILE_SIZE, img->cachefile); + } + else + { + fputs("DEBUG: Clearing cache tile...\n", stderr); + + memset(ic->pixels, 0, bpp * TILE_SIZE * TILE_SIZE); + } + } + + if (ic == img->first) + img->first = ic->next; + else if (img->first == NULL) + img->first = ic; + + if (ic != img->last) + { + if (img->last != NULL) + img->last->next = ic; + + ic->prev = img->last; + img->last = ic; + } + + ic->next = NULL; + + return (ic->pixels + bpp * (y * TILE_SIZE + x)); +} + + +/* + * 'flush_tile()' - Flush the least-recently-used tile in the cache. + */ + +static void +flush_tile(image_t *img) /* I - Image */ +{ + int bpp; /* Bytes per pixel */ + itile_t *tile; /* Pointer to tile */ + + + + bpp = ImageGetDepth(img); + tile = img->first->tile; + + if (!tile->dirty) + { + tile->ic = NULL; + return; + } + + if (img->cachefile == NULL) + { + cupsTempFile(img->cachename, sizeof(img->cachename)); + + fprintf(stderr, "DEBUG: Creating swap file \"%s\"...\n", img->cachename); + + if ((img->cachefile = fopen(img->cachename, "wb+")) == NULL) + { + perror("ERROR: Unable to create image swap file"); + tile->ic = NULL; + tile->dirty = 0; + return; + } + } + + if (tile->pos >= 0) + { + if (ftell(img->cachefile) != tile->pos) + if (fseek(img->cachefile, tile->pos, SEEK_SET)) + { + perror("ERROR: Unable to seek in swap file"); + tile->ic = NULL; + tile->dirty = 0; + return; + } + } + else + { + if (fseek(img->cachefile, 0, SEEK_END)) + { + perror("ERROR: Unable to append to swap file"); + tile->ic = NULL; + tile->dirty = 0; + return; + } + + tile->pos = ftell(img->cachefile); + } + + + if (fwrite(tile->ic->pixels, bpp, TILE_SIZE * TILE_SIZE, img->cachefile) < 1) + perror("ERROR: Unable to write tile to swap file"); + else + fprintf(stderr, "DEBUG: Wrote tile at position %d...\n", tile->pos); + + tile->ic = NULL; + tile->dirty = 0; +} + + +/* + * End of "$Id$". + */ diff --git a/filter/image.h b/filter/image.h new file mode 100644 index 0000000000..b4969e48a9 --- /dev/null +++ b/filter/image.h @@ -0,0 +1,225 @@ +/* + * "$Id$" + * + * Image library definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _IMAGE_H_ +# define _IMAGE_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# include +# include +# include + + +/* + * Colorspaces... + */ + +# define IMAGE_CMYK -4 /* Cyan, magenta, yellow, and black */ +# define IMAGE_CMY -3 /* Cyan, magenta, and yellow */ +# define IMAGE_BLACK -1 /* Black */ +# define IMAGE_WHITE 1 /* White (luminance) */ +# define IMAGE_RGB 3 /* Red, green, and blue */ + +/* + * Tile definitions... + */ + +# define TILE_SIZE 256 /* 256x256 pixel tiles */ +# define TILE_MINIMUM 10 /* Minimum number of tiles */ + +/* + * min/max/abs macros... + */ + +#ifndef max +# define max(a,b) ((a) > (b) ? (a) : (b)) +#endif /* !max */ +#ifndef min +# define min(a,b) ((a) < (b) ? (a) : (b)) +#endif /* !min */ +#ifndef abs +# define abs(a) ((a) < 0 ? -(a) : (a)) +#endif /* !abs */ + + +/* + * Image byte type... + */ + +typedef unsigned char ib_t; + +/* + * Tile cache structure... + */ + +typedef struct ic_str +{ + struct ic_str *prev, /* Previous tile in cache */ + *next; /* Next tile in cache */ + void *tile; /* Tile this is attached to */ + ib_t *pixels; /* Pixel data */ +} ic_t; + +/* + * Tile structure... + */ + +typedef struct +{ + int dirty; /* True if tile is dirty */ + long pos; /* Position of tile on disk (-1 if not written) */ + ic_t *ic; /* Pixel data */ +} itile_t; + +/* + * Image structure... + */ + +typedef struct +{ + int colorspace; /* Colorspace of image */ + unsigned xsize, /* Width of image in pixels */ + ysize, /* Height of image in pixels */ + xppi, /* X resolution in pixels-per-inch */ + yppi, /* Y resolution in pixels-per-inch */ + num_ics, /* Number of cached tiles */ + max_ics; /* Maximum number of cached tiles */ + itile_t **tiles; /* Tiles in image */ + ic_t *first, /* First cached tile in image */ + *last; /* Last cached tile in image */ + FILE *cachefile; /* Tile cache file */ + char cachename[256]; /* Tile cache filename */ +} image_t; + +/* + * Image row zooming structure... + */ + +typedef struct +{ + image_t *img; /* Image to zoom */ + unsigned xorig, + yorig, + width, /* Width of input area */ + height, /* Height of input area */ + depth, /* Number of bytes per pixel */ + rotated, /* Non-zero if image needs to be rotated */ + xsize, /* Width of output image */ + ysize, /* Height of output image */ + xmax, /* Maximum input image X position */ + ymax, /* Maximum input image Y position */ + xmod, /* Threshold for Bresenheim rounding */ + ymod; /* ... */ + int xstep, /* Amount to step for each pixel along X */ + xincr, + instep, /* Amount to step pixel pointer along X */ + inincr, + ystep, /* Amount to step for each pixel along Y */ + yincr, + row; /* Current row */ + ib_t *rows[2], /* Horizontally scaled pixel data */ + *in; /* Unscaled input pixel data */ +} izoom_t; + + +/* + * Basic image functions... + */ + +extern image_t *ImageOpen(char *filename, int primary, int secondary, + int saturation, int hue, const ib_t *lut); +extern void ImageClose(image_t *img); +extern void ImageSetMaxTiles(image_t *img, int max_tiles); +extern void ImageSetProfile(float d, float g, float matrix[3][3]); + +#define ImageGetDepth(img) ((img)->colorspace < 0 ? -(img)->colorspace : (img)->colorspace) +extern int ImageGetCol(image_t *img, int x, int y, int height, ib_t *pixels); +extern int ImageGetRow(image_t *img, int x, int y, int width, ib_t *pixels); +extern int ImagePutCol(image_t *img, int x, int y, int height, const ib_t *pixels); +extern int ImagePutRow(image_t *img, int x, int y, int width, const ib_t *pixels); + +/* + * File formats... + */ + +extern int ImageReadGIF(image_t *img, FILE *fp, int primary, int secondary, + int saturation, int hue, const ib_t *lut); +extern int ImageReadJPEG(image_t *img, FILE *fp, int primary, int secondary, + int saturation, int hue, const ib_t *lut); +extern int ImageReadPNG(image_t *img, FILE *fp, int primary, int secondary, + int saturation, int hue, const ib_t *lut); +extern int ImageReadPNM(image_t *img, FILE *fp, int primary, int secondary, + int saturation, int hue, const ib_t *lut); +extern int ImageReadPhotoCD(image_t *img, FILE *fp, int primary, + int secondary, int saturation, int hue, + const ib_t *lut); +extern int ImageReadSGI(image_t *img, FILE *fp, int primary, int secondary, + int saturation, int hue, const ib_t *lut); +extern int ImageReadSunRaster(image_t *img, FILE *fp, int primary, + int secondary, int saturation, int hue, + const ib_t *lut); +extern int ImageReadTIFF(image_t *img, FILE *fp, int primary, int secondary, + int saturation, int hue, const ib_t *lut); + +/* + * Colorspace conversions... + */ + +extern void ImageWhiteToWhite(const ib_t *in, ib_t *out, int count); +extern void ImageWhiteToRGB(const ib_t *in, ib_t *out, int count); +extern void ImageWhiteToBlack(const ib_t *in, ib_t *out, int count); +extern void ImageWhiteToCMY(const ib_t *in, ib_t *out, int count); +extern void ImageWhiteToCMYK(const ib_t *in, ib_t *out, int count); + +extern void ImageRGBToWhite(const ib_t *in, ib_t *out, int count); +extern void ImageRGBToRGB(const ib_t *in, ib_t *out, int count); +extern void ImageRGBToBlack(const ib_t *in, ib_t *out, int count); +extern void ImageRGBToCMY(const ib_t *in, ib_t *out, int count); +extern void ImageRGBToCMYK(const ib_t *in, ib_t *out, int count); + +extern void ImageRGBAdjust(ib_t *pixels, int count, int saturation, int hue); + +extern void ImageLut(ib_t *pixels, int count, const ib_t *lut); + +/* + * Image scaling operations... + */ + +extern izoom_t *ImageZoomAlloc(image_t *img, int x0, int y0, int x1, int y1, + int xsize, int ysize, int rotated); +extern void ImageZoomFill(izoom_t *z, int iy); +extern void ImageZoomQFill(izoom_t *z, int iy); +extern void ImageZoomFree(izoom_t *z); + + +#endif /* !_IMAGE_H_ */ + +/* + * End of "$Id$". + */ diff --git a/filter/imagetops.c b/filter/imagetops.c new file mode 100644 index 0000000000..e6c28eca00 --- /dev/null +++ b/filter/imagetops.c @@ -0,0 +1,494 @@ +/* + * "$Id$" + * + * Image file to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry... + * ps_hex() - Print binary data as a series of hexadecimal numbers. + * ps_ascii85() - Print binary data as a series of base-85 numbers. + */ + +/* + * Include necessary headers... + */ + +#include "common.h" +#include "image.h" +#include + + +/* + * Globals... + */ + +int Flip = 0, /* Flip/mirror pages */ + Collate = 0, /* Collate copies? */ + Copies = 1; /* Number of copies */ + + +/* + * Local functions... + */ + +static void ps_hex(ib_t *, int); +static void ps_ascii85(ib_t *, int, int); + + +/* + * 'main()' - Main entry... + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + image_t *img; /* Image to print */ + float xprint, /* Printable area */ + yprint, + xinches, /* Total size in inches */ + yinches; + float xsize, /* Total size in points */ + ysize; + int xpages, /* # x pages */ + ypages, /* # y pages */ + xpage, /* Current x page */ + ypage, /* Current y page */ + page; /* Current page number */ + int x0, y0, /* Corners of the page in image coords */ + x1, y1; + ib_t *row; /* Current row */ + int y; /* Current Y coordinate in image */ + int colorspace; /* Output colorspace */ + int out_offset, /* Offset into output buffer */ + out_length; /* Length of output buffer */ + ppd_file_t *ppd; /* PPD file */ + int num_options; /* Number of print options */ + cups_option_t *options; /* Print options */ + const char *val; /* Option value */ + int slowcollate; /* Collate copies the slow way */ + float g; /* Gamma correction value */ + float b; /* Brightness factor */ + float zoom; /* Zoom facter */ + int ppi; /* Pixels-per-inch */ + int hue, sat; /* Hue and saturation adjustment */ + int realcopies; /* Real copies being printed */ + + + if (argc != 7) + { + fputs("ERROR: imagetops job-id user title copies options file\n", stderr); + return (1); + } + + /* + * Process command-line options and write the prolog... + */ + + zoom = 0.0; + ppi = 0; + hue = 0; + sat = 100; + g = 1.0; + b = 1.0; + + Copies = atoi(argv[4]); + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + ppd = SetCommonOptions(num_options, options, 1); + + ppdMarkDefaults(ppd); + cupsMarkOptions(ppd, num_options, options); + + if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) + { + /* + * This IPP attribute is unnecessarily complicated... + * + * single-document, separate-documents-collated-copies, and + * single-document-new-sheet all require collated copies. + * + * separate-documents-collated-copies allows for uncollated copies. + */ + + Collate = strcmp(val, "separate-documents-collated-copies") != 0; + } + + if ((val = cupsGetOption("Collate", num_options, options)) != NULL && + strcmp(val, "True") == 0) + Collate = 1; + + if ((val = cupsGetOption("gamma", num_options, options)) != NULL) + g = atoi(val) * 0.001f; + + if ((val = cupsGetOption("brightness", num_options, options)) != NULL) + b = atoi(val) * 0.01f; + + if ((val = cupsGetOption("scaling", num_options, options)) != NULL) + zoom = atoi(val) * 0.01; + + if ((val = cupsGetOption("ppi", num_options, options)) != NULL) + ppi = atoi(val); + + if ((val = cupsGetOption("saturation", num_options, options)) != NULL) + sat = atoi(val); + + if ((val = cupsGetOption("hue", num_options, options)) != NULL) + hue = atoi(val); + + /* + * Open the input image to print... + */ + + colorspace = ColorDevice ? IMAGE_RGB : IMAGE_WHITE; + + if ((img = ImageOpen(argv[6], colorspace, IMAGE_WHITE, sat, hue, NULL)) == NULL) + { + fputs("ERROR: Unable to open image file for printing!\n", stderr); + ppdClose(ppd); + return (1); + } + + colorspace = img->colorspace; + + /* + * Scale as necessary... + */ + + xprint = (PageRight - PageLeft) / 72.0; + yprint = (PageTop - PageBottom) / 72.0; + + if (zoom == 0.0 && ppi == 0) + ppi = img->xppi; + + if (ppi > 0) + { + /* + * Scale the image as neccesary to match the desired pixels-per-inch. + */ + + xinches = (float)img->xsize / (float)ppi; + yinches = (float)img->ysize / (float)ppi; + } + else + { + /* + * Scale percentage of page size... + */ + + xsize = xprint * zoom; + ysize = xsize * img->ysize / img->xsize; + + if (ysize > (yprint * zoom)) + { + ysize = yprint * zoom; + xsize = ysize * img->xsize / img->ysize; + } + + xinches = xsize; + yinches = ysize; + } + + xpages = ceil(xinches / xprint); + ypages = ceil(yinches / yprint); + + /* + * See if we need to collate, and if so how we need to do it... + */ + + if (xpages == 1 && ypages == 1) + Collate = 0; + + slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL; + + /* + * Write any "exit server" options that have been selected... + */ + + ppdEmit(ppd, stdout, PPD_ORDER_EXIT); + + /* + * Write any JCL commands that are needed to print PostScript code... + */ + + if (ppd != NULL && ppd->jcl_begin && ppd->jcl_ps) + { + fputs(ppd->jcl_begin, stdout); + ppdEmit(ppd, stdout, PPD_ORDER_JCL); + fputs(ppd->jcl_ps, stdout); + } + + /* + * Start sending the document with any commands needed... + */ + + puts("%!"); + + if (ppd != NULL && ppd->patches != NULL) + puts(ppd->patches); + + ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT); + ppdEmit(ppd, stdout, PPD_ORDER_ANY); + ppdEmit(ppd, stdout, PPD_ORDER_PROLOG); + + if (g != 1.0 || b != 1.0) + printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } " + "ifelse %.3f mul } bind settransfer\n", g, b); + + if (Copies > 1 && !slowcollate) + { + printf("/#copies %d def\n", Copies); + realcopies = Copies; + Copies = 1; + } + else + realcopies = 1; + + /* + * Output the pages... + */ + + xprint = xinches / xpages; + yprint = yinches / ypages; + row = malloc(img->xsize * abs(colorspace) + 3); + + for (page = 1; Copies > 0; Copies --) + for (xpage = 0; xpage < xpages; xpage ++) + for (ypage = 0; ypage < ypages; ypage ++, page ++) + { + fprintf(stderr, "PAGE: %d %d\n", page, realcopies); + fprintf(stderr, "INFO: Printing page %d...\n", page); + + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + + puts("gsave"); + + if (Flip) + printf("%.0f 0 translate -1 1 scale\n", PageWidth); + + switch (Orientation) + { + case 1 : /* Landscape */ + printf("%.0f 0 translate 90 rotate\n", PageLength); + break; + case 2 : /* Reverse Portrait */ + printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); + break; + case 3 : /* Reverse Landscape */ + printf("0 %.0f translate -90 rotate\n", PageWidth); + break; + } + + x0 = img->xsize * xpage / xpages; + x1 = img->xsize * (xpage + 1) / xpages - 1; + y0 = img->ysize * ypage / ypages; + y1 = img->ysize * (ypage + 1) / ypages - 1; + + printf("%.1f %.1f translate\n", PageLeft, PageBottom + 72.0 * yprint); + printf("%.3f %.3f scale\n\n", + xprint * 72.0 / (x1 - x0 + 1), + yprint * 72.0 / (y1 - y0 + 1)); + + if (LanguageLevel == 1) + { + printf("/picture %d string def\n", (x1 - x0 + 1) * abs(colorspace)); + printf("%d %d 8[1 0 0 -1 0 1]", (x1 - x0 + 1), (y1 - y0 + 1)); + + if (colorspace == IMAGE_WHITE) + puts("{currentfile picture readhexstring pop} image"); + else + puts("{currentfile picture readhexstring pop} false 3 colorimage"); + + for (y = y0; y <= y1; y ++) + { + ImageGetRow(img, x0, y, x1 - x0 + 1, row); + ps_hex(row, (x1 - x0 + 1) * abs(colorspace)); + } + } + else + { + if (colorspace == IMAGE_WHITE) + puts("/DeviceGray setcolorspace"); + else + puts("/DeviceRGB setcolorspace"); + + printf("<<" + "/ImageType 1" + "/Width %d" + "/Height %d" + "/BitsPerComponent 8", + x1 - x0 + 1, y1 - y0 + 1); + + if (colorspace == IMAGE_WHITE) + fputs("/Decode[0 1]", stdout); + else + fputs("/Decode[0 1 0 1 0 1]", stdout); + + fputs("/DataSource currentfile /ASCII85Decode filter", stdout); + + if (((x1 - x0 + 1) / xprint) < 100.0) + fputs("/Interpolate true", stdout); + + puts("/ImageMatrix[1 0 0 -1 0 1]>>image"); + + for (y = y0, out_offset = 0; y <= y1; y ++) + { + ImageGetRow(img, x0, y, x1 - x0 + 1, row + out_offset); + + out_length = (x1 - x0 + 1) * abs(colorspace) + out_offset; + out_offset = out_length & 3; + + ps_ascii85(row, out_length, y == y1); + + if (out_offset > 0) + memcpy(row, row + out_length - out_offset, out_offset); + } + } + + puts("grestore"); + puts("showpage"); + } + + /* + * End the job with the appropriate JCL command or CTRL-D otherwise. + */ + + if (ppd != NULL && ppd->jcl_end) + fputs(ppd->jcl_end, stdout); + else + putchar(0x04); + + /* + * Close files... + */ + + ImageClose(img); + ppdClose(ppd); + + return (0); +} + + +/* + * 'ps_hex()' - Print binary data as a series of hexadecimal numbers. + */ + +static void +ps_hex(ib_t *data, /* I - Data to print */ + int length) /* I - Number of bytes to print */ +{ + int col; + static char *hex = "0123456789ABCDEF"; + + + col = 0; + + while (length > 0) + { + /* + * Put the hex chars out to the file; note that we don't use printf() + * for speed reasons... + */ + + putchar(hex[*data >> 4]); + putchar(hex[*data & 15]); + + data ++; + length --; + + col = (col + 1) & 31; + if (col == 0 && length > 0) + putchar('\n'); + } + + putchar('\n'); +} + + +/* + * 'ps_ascii85()' - Print binary data as a series of base-85 numbers. + */ + +static void +ps_ascii85(ib_t *data, /* I - Data to print */ + int length, /* I - Number of bytes to print */ + int last_line) /* I - Last line of raster data? */ +{ + int i; /* Looping var */ + unsigned b; /* Binary data word */ + unsigned char c[5]; /* ASCII85 encoded chars */ + + + while (length > 3) + { + b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]; + + if (b == 0) + putchar('z'); + else + { + c[4] = (b % 85) + '!'; + b /= 85; + c[3] = (b % 85) + '!'; + b /= 85; + c[2] = (b % 85) + '!'; + b /= 85; + c[1] = (b % 85) + '!'; + b /= 85; + c[0] = b + '!'; + + fwrite(c, 5, 1, stdout); + } + + data += 4; + length -= 4; + } + + if (last_line) + { + if (length > 0) + { + for (b = 0, i = length; i > 0; b = (b << 8) | data[0], data ++, i --); + + c[4] = (b % 85) + '!'; + b /= 85; + c[3] = (b % 85) + '!'; + b /= 85; + c[2] = (b % 85) + '!'; + b /= 85; + c[1] = (b % 85) + '!'; + b /= 85; + c[0] = b + '!'; + + fwrite(c, length + 1, 1, stdout); + } + + puts("~>"); + } +} + + +/* + * End of "$Id$". + */ diff --git a/filter/imagetoraster.c b/filter/imagetoraster.c new file mode 100644 index 0000000000..44755df226 --- /dev/null +++ b/filter/imagetoraster.c @@ -0,0 +1,3852 @@ +/* + * "$Id$" + * + * Image file to raster filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry... + * format_CMY() - Convert image data to CMY. + * format_CMYK() - Convert image data to CMYK. + * format_K() - Convert image data to black. + * format_KCMY() - Convert image data to KCMY. + * format_KCMYcm() - Convert image data to KCMYcm. + * format_RGBA() - Convert image data to RGBA. + * format_W() - Convert image data to luminance. + * format_YMC() - Convert image data to YMC. + * format_YMCK() - Convert image data to YMCK. + * make_lut() - Make a lookup table given gamma and brightness values. + */ + +/* + * Include necessary headers... + */ + +/* + * Include necessary headers... + */ + +#include "common.h" +#include "image.h" +#include +#include + + +/* + * Globals... + */ + +int Flip = 0, /* Flip/mirror pages */ + Collate = 0, /* Collate copies? */ + Copies = 1; /* Number of copies */ +int Floyd16x16[16][16] = /* Traditional Floyd ordered dither */ + { + { 0, 128, 32, 160, 8, 136, 40, 168, + 2, 130, 34, 162, 10, 138, 42, 170 }, + { 192, 64, 224, 96, 200, 72, 232, 104, + 194, 66, 226, 98, 202, 74, 234, 106 }, + { 48, 176, 16, 144, 56, 184, 24, 152, + 50, 178, 18, 146, 58, 186, 26, 154 }, + { 240, 112, 208, 80, 248, 120, 216, 88, + 242, 114, 210, 82, 250, 122, 218, 90 }, + { 12, 140, 44, 172, 4, 132, 36, 164, + 14, 142, 46, 174, 6, 134, 38, 166 }, + { 204, 76, 236, 108, 196, 68, 228, 100, + 206, 78, 238, 110, 198, 70, 230, 102 }, + { 60, 188, 28, 156, 52, 180, 20, 148, + 62, 190, 30, 158, 54, 182, 22, 150 }, + { 252, 124, 220, 92, 244, 116, 212, 84, + 254, 126, 222, 94, 246, 118, 214, 86 }, + { 3, 131, 35, 163, 11, 139, 43, 171, + 1, 129, 33, 161, 9, 137, 41, 169 }, + { 195, 67, 227, 99, 203, 75, 235, 107, + 193, 65, 225, 97, 201, 73, 233, 105 }, + { 51, 179, 19, 147, 59, 187, 27, 155, + 49, 177, 17, 145, 57, 185, 25, 153 }, + { 243, 115, 211, 83, 251, 123, 219, 91, + 241, 113, 209, 81, 249, 121, 217, 89 }, + { 15, 143, 47, 175, 7, 135, 39, 167, + 13, 141, 45, 173, 5, 133, 37, 165 }, + { 207, 79, 239, 111, 199, 71, 231, 103, + 205, 77, 237, 109, 197, 69, 229, 101 }, + { 63, 191, 31, 159, 55, 183, 23, 151, + 61, 189, 29, 157, 53, 181, 21, 149 }, + { 254, 127, 223, 95, 247, 119, 215, 87, + 253, 125, 221, 93, 245, 117, 213, 85 } + }; +int Floyd8x8[8][8] = + { + { 0, 32, 8, 40, 2, 34, 10, 42 }, + { 48, 16, 56, 24, 50, 18, 58, 26 }, + { 12, 44, 4, 36, 14, 46, 6, 38 }, + { 60, 28, 52, 20, 62, 30, 54, 22 }, + { 3, 35, 11, 43, 1, 33, 9, 41 }, + { 51, 19, 59, 27, 49, 17, 57, 25 }, + { 15, 47, 7, 39, 13, 45, 5, 37 }, + { 63, 31, 55, 23, 61, 29, 53, 21 } + }; +int Floyd4x4[4][4] = + { + { 0, 8, 2, 10 }, + { 12, 4, 14, 6 }, + { 3, 11, 1, 9 }, + { 15, 7, 13, 5 } + }; + +ib_t OnPixels[256], /* On-pixel LUT */ + OffPixels[256]; /* Off-pixel LUT */ +int Planes[] = /* Number of planes for each colorspace */ + { 1, 3, 4, 1, 3, 3, 4, 4, 4, 6, 4, 4, 1, 1, 1 }; + + +/* + * Local functions... + */ + +static void exec_choice(cups_page_header_t *header, ppd_choice_t *choice); +static void format_CMY(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void format_CMYK(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void format_K(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void format_KCMYcm(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void format_KCMY(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +#define format_RGB format_CMY +static void format_RGBA(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void format_W(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void format_YMC(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void format_YMCK(cups_page_header_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, ib_t *r0, ib_t *r1); +static void make_lut(ib_t *, int, float, float); + + +/* + * 'main()' - Main entry... + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + image_t *img; /* Image to print */ + float xprint, /* Printable area */ + yprint, + xinches, /* Total size in inches */ + yinches; + float xsize, /* Total size in points */ + ysize; + int xpages, /* # x pages */ + ypages, /* # y pages */ + xpage, /* Current x page */ + ypage, /* Current y page */ + xtemp, /* Bitmap width in pixels */ + ytemp, /* Bitmap height in pixels */ + page; /* Current page number */ + int x0, y0, /* Corners of the page in image coords */ + x1, y1; + ppd_file_t *ppd; /* PPD file */ + ppd_choice_t *choice; /* PPD option choice */ + char *resolution, /* Output resolution */ + *media_type; /* Media type */ + ppd_profile_t *profile; /* Color profile */ + cups_raster_t *ras; /* Raster stream */ + cups_page_header_t header; /* Page header */ + int num_options; /* Number of print options */ + cups_option_t *options; /* Print options */ + const char *val; /* Option value */ + int slowcollate, /* Collate copies the slow way */ + slowcopies; /* Make copies the "slow" way? */ + float g; /* Gamma correction value */ + float b; /* Brightness factor */ + float zoom; /* Zoom facter */ + int ppi; /* Pixels-per-inch */ + int hue, sat; /* Hue and saturation adjustment */ + izoom_t *z; /* ImageZoom buffer */ + int primary, /* Primary image colorspace */ + secondary; /* Secondary image colorspace */ + ib_t *row, /* Current row */ + *r0, /* Top row */ + *r1; /* Bottom row */ + int y, /* Current Y coordinate on page */ + iy, /* Current Y coordinate in image */ + last_iy, /* Previous Y coordinate in image */ + yerr0, /* Top Y error value */ + yerr1, /* Bottom Y error value */ + blank; /* Blank value */ + ib_t lut[256]; /* Gamma/brightness LUT */ + int plane, /* Current color plane */ + num_planes; /* Number of color planes */ + + + if (argc != 7) + { + fputs("ERROR: imagetoraster job-id user title copies options file\n", stderr); + return (1); + } + + fprintf(stderr, "INFO: %s %s %s %s %s %s %s\n", argv[0], argv[1], argv[2], + argv[3], argv[4], argv[5], argv[6]); + + /* + * Process command-line options and write the prolog... + */ + + zoom = 0.0; + ppi = 0; + hue = 0; + sat = 100; + g = 1.0; + b = 1.0; + + Copies = atoi(argv[4]); + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + ppd = SetCommonOptions(num_options, options, 0); + + ppdMarkDefaults(ppd); + cupsMarkOptions(ppd, num_options, options); + + if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) + { + /* + * This IPP attribute is unnecessarily complicated... + * + * single-document, separate-documents-collated-copies, and + * single-document-new-sheet all require collated copies. + * + * separate-documents-collated-copies allows for uncollated copies. + */ + + Collate = strcmp(val, "separate-documents-collated-copies") != 0; + } + + if ((val = cupsGetOption("Collate", num_options, options)) != NULL && + strcmp(val, "True") == 0) + Collate = 1; + + if ((val = cupsGetOption("gamma", num_options, options)) != NULL) + g = atoi(val) * 0.001f; + + if ((val = cupsGetOption("brightness", num_options, options)) != NULL) + b = atoi(val) * 0.01f; + + if ((val = cupsGetOption("scaling", num_options, options)) != NULL) + zoom = atoi(val) * 0.01; + + if ((val = cupsGetOption("ppi", num_options, options)) != NULL) + ppi = atoi(val); + + if ((val = cupsGetOption("saturation", num_options, options)) != NULL) + sat = atoi(val); + + if ((val = cupsGetOption("hue", num_options, options)) != NULL) + hue = atoi(val); + + /* + * Set the needed options in the page header... + */ + + memset(&header, 0, sizeof(header)); + header.HWResolution[0] = 100; + header.HWResolution[1] = 100; + header.cupsBitsPerColor = 1; + header.cupsColorOrder = CUPS_ORDER_CHUNKED; + header.cupsColorSpace = CUPS_CSPACE_RGB; + + if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL) + exec_choice(&header, choice); + + if ((choice = ppdFindMarkedChoice(ppd, "InputSlot")) != NULL) + exec_choice(&header, choice); + + if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL) + { + exec_choice(&header, choice); + + media_type = choice->choice; + } + else + media_type = ""; + + if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL) + { + exec_choice(&header, choice); + + resolution = choice->choice; + } + else + resolution = ""; + + /* + * Choose the appropriate colorspace... + */ + + switch (header.cupsColorSpace) + { + case CUPS_CSPACE_W : + primary = IMAGE_WHITE; + secondary = IMAGE_WHITE; + header.cupsBitsPerPixel = header.cupsBitsPerColor; + break; + + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_RGBA : + primary = IMAGE_RGB; + secondary = IMAGE_RGB; + + if (header.cupsColorOrder == CUPS_ORDER_CHUNKED) + { + if (header.cupsBitsPerColor >= 8) + header.cupsBitsPerPixel = header.cupsBitsPerColor * 3; + else + header.cupsBitsPerPixel = header.cupsBitsPerColor * 4; + } + else + header.cupsBitsPerPixel = header.cupsBitsPerColor; + break; + + case CUPS_CSPACE_K : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + primary = IMAGE_BLACK; + secondary = IMAGE_BLACK; + header.cupsBitsPerPixel = header.cupsBitsPerColor; + break; + + default : + primary = IMAGE_CMYK; + secondary = IMAGE_CMYK; + + if (header.cupsColorOrder == CUPS_ORDER_CHUNKED) + header.cupsBitsPerPixel = header.cupsBitsPerColor * 4; + else + header.cupsBitsPerPixel = header.cupsBitsPerColor; + break; + + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + primary = IMAGE_CMY; + secondary = IMAGE_CMY; + + if (header.cupsColorOrder == CUPS_ORDER_CHUNKED) + { + if (header.cupsBitsPerColor >= 8) + header.cupsBitsPerPixel = 24; + else + header.cupsBitsPerPixel = header.cupsBitsPerColor * 4; + } + else + header.cupsBitsPerPixel = header.cupsBitsPerColor; + break; + + case CUPS_CSPACE_KCMYcm : + if (header.cupsBitsPerPixel == 1) + { + primary = IMAGE_CMY; + secondary = IMAGE_CMY; + + if (header.cupsColorOrder == CUPS_ORDER_CHUNKED) + header.cupsBitsPerPixel = 8; + else + header.cupsBitsPerPixel = 1; + } + else + { + primary = IMAGE_CMYK; + secondary = IMAGE_CMYK; + + if (header.cupsColorOrder == CUPS_ORDER_CHUNKED) + header.cupsBitsPerPixel = header.cupsBitsPerColor * 4; + else + header.cupsBitsPerPixel = header.cupsBitsPerColor; + } + break; + } + + /* + * Find a color profile matching the current options... + */ + + if (ppd != NULL) + { + fprintf(stderr, "DEBUG: Searching for profile \"%s/%s\"...\n", + resolution, media_type); + + for (i = 0, profile = ppd->profiles; i < ppd->num_profiles; i ++, profile ++) + { + fprintf(stderr, "DEBUG: \"%s/%s\" = ", profile->resolution, + profile->media_type); + + if ((strcmp(profile->resolution, resolution) == 0 || + profile->resolution[0] == '-') && + (strcmp(profile->media_type, media_type) == 0 || + profile->media_type[0] == '-')) + { + fputs("MATCH!\n", stderr); + break; + } + else + fputs("no.\n", stderr); + } + + /* + * If we found a color profile, use it! + */ + + if (i < ppd->num_profiles) + ImageSetProfile(profile->density, profile->gamma, profile->matrix); + } + + /* + * Create a gamma/brightness LUT... + */ + + make_lut(lut, primary, g, b); + + /* + * Open the input image to print... + */ + + fputs("INFO: Loading image file...\n", stderr); + + if ((img = ImageOpen(argv[6], primary, secondary, sat, hue, lut)) == NULL) + { + fputs("ERROR: Unable to open image file for printing!\n", stderr); + ppdClose(ppd); + return (1); + } + + /* + * Scale as necessary... + */ + + if (Orientation & 1) + { + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + } + else + { + xprint = (PageRight - PageLeft) / 72.0; + yprint = (PageTop - PageBottom) / 72.0; + } + + if (zoom == 0.0 && ppi == 0) + ppi = img->xppi; + + if (ppi > 0) + { + /* + * Scale the image as neccesary to match the desired pixels-per-inch. + */ + + xinches = (float)img->xsize / (float)ppi; + yinches = (float)img->ysize / (float)ppi; + } + else + { + /* + * Scale percentage of page size... + */ + + xsize = xprint * zoom; + ysize = xsize * img->ysize / img->xsize; + + if (ysize > (yprint * zoom)) + { + ysize = yprint * zoom; + xsize = ysize * img->xsize / img->ysize; + } + + xinches = xsize; + yinches = ysize; + } + + xpages = ceil(xinches / xprint); + ypages = ceil(yinches / yprint); + + /* + * Compute the bitmap size... + */ + + xprint = xinches / xpages; + yprint = yinches / ypages; + + if ((val = cupsGetOption("Page", num_options, options)) != NULL && + strncmp(val, "Custom.", 7) == 0) + { + if (Orientation & 1) + { + header.cupsWidth = yprint * header.HWResolution[0]; + header.cupsHeight = xprint * header.HWResolution[1]; + header.PageSize[0] = yprint * 72.0; + header.PageSize[1] = xprint * 72.0; + } + else + { + header.cupsWidth = xprint * header.HWResolution[0]; + header.cupsHeight = yprint * header.HWResolution[1]; + header.PageSize[0] = xprint * 72.0; + header.PageSize[1] = yprint * 72.0; + } + } + else + { + header.cupsWidth = (PageRight - PageLeft) * header.HWResolution[0] / 72.0; + header.cupsHeight = (PageTop - PageBottom) * header.HWResolution[1] / 72.0; + header.PageSize[0] = PageWidth; + header.PageSize[1] = PageLength; + } + + switch (header.cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + header.cupsBytesPerLine = (header.cupsBitsPerPixel * + header.cupsWidth + 7) / 8; + num_planes = 1; + break; + + case CUPS_ORDER_BANDED : + if (header.cupsColorSpace == CUPS_CSPACE_KCMYcm && + header.cupsBitsPerColor > 1) + header.cupsBytesPerLine = (header.cupsBitsPerPixel * + header.cupsWidth + 7) / 8 * 4; + else + header.cupsBytesPerLine = (header.cupsBitsPerPixel * + header.cupsWidth + 7) / 8 * + Planes[header.cupsColorSpace]; + num_planes = 1; + break; + + case CUPS_ORDER_PLANAR : + header.cupsBytesPerLine = (header.cupsBitsPerPixel * + header.cupsWidth + 7) / 8; + num_planes = Planes[header.cupsColorSpace]; + break; + } + + /* + * See if we need to collate, and if so how we need to do it... + */ + + if (xpages == 1 && ypages == 1) + Collate = 0; + + slowcollate = Collate && ppdFindOption(ppd, "Collate") == NULL; + if (ppd != NULL) + slowcopies = ppd->manual_copies; + else + slowcopies = 1; + + if (Copies > 1 && !slowcollate && !slowcopies) + { + header.Collate = (cups_bool_t)Collate; + header.NumCopies = Copies; + + Copies = 1; + } + else + header.NumCopies = 1; + + /* + * Create the dithering lookup tables... + */ + + OnPixels[0] = 0x00; + OnPixels[255] = 0xff; + OffPixels[0] = 0x00; + OffPixels[255] = 0xff; + + switch (header.cupsBitsPerColor) + { + case 2 : + for (i = 1; i < 255; i ++) + { + OnPixels[i] = 0x55 * (i / 85 + 1); + OffPixels[i] = 0x55 * (i / 64); + } + break; + case 4 : + for (i = 1; i < 255; i ++) + { + OnPixels[i] = 17 * (i / 17 + 1); + OffPixels[i] = 17 * (i / 16); + } + + OnPixels[255] = OffPixels[255] = 0xff; + break; + } + + /* + * Output the pages... + */ + + fprintf(stderr, "DEBUG: cupsWidth = %d\n", header.cupsWidth); + fprintf(stderr, "DEBUG: cupsHeight = %d\n", header.cupsHeight); + fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", header.cupsBitsPerColor); + fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", header.cupsBitsPerPixel); + fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", header.cupsBytesPerLine); + fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", header.cupsColorOrder); + fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", header.cupsColorSpace); + fprintf(stderr, "DEBUG: img->colorspace = %d\n", img->colorspace); + + row = malloc(2 * header.cupsBytesPerLine); + ras = cupsRasterOpen(1, CUPS_RASTER_WRITE); + blank = img->colorspace < 0 ? 0 : ~0; + + for (i = 0, page = 1; i < Copies; i ++) + for (xpage = 0; xpage < xpages; xpage ++) + for (ypage = 0; ypage < ypages; ypage ++, page ++) + { + fprintf(stderr, "INFO: Formatting page %d...\n", page); + + if (Orientation & 1) + { + x0 = img->xsize * ypage / ypages; + x1 = img->xsize * (ypage + 1) / ypages - 1; + y0 = img->ysize * xpage / xpages; + y1 = img->ysize * (xpage + 1) / xpages - 1; + + xtemp = header.HWResolution[0] * yprint; + ytemp = header.HWResolution[1] * xprint; + } + else + { + x0 = img->xsize * xpage / xpages; + x1 = img->xsize * (xpage + 1) / xpages - 1; + y0 = img->ysize * ypage / ypages; + y1 = img->ysize * (ypage + 1) / ypages - 1; + + xtemp = header.HWResolution[0] * xprint; + ytemp = header.HWResolution[1] * yprint; + } + + cupsRasterWriteHeader(ras, &header); + + for (plane = 0; plane < num_planes; plane ++) + { + /* + * Initialize the image "zoom" engine... + */ + + z = ImageZoomAlloc(img, x0, y0, x1, y1, xtemp, ytemp, Orientation & 1); + + /* + * Write leading blank space as needed... + */ + + if (header.cupsHeight > z->ysize && Orientation < 2) + { + memset(row, blank, header.cupsBytesPerLine); + + for (y = header.cupsHeight - z->ysize; y > 0; y --) + { + if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) < + header.cupsBytesPerLine) + { + fputs("ERROR: Unable to write raster data to driver!\n", stderr); + ImageClose(img); + exit(1); + } + } + } + + /* + * Then write image data... + */ + + for (y = z->ysize, yerr0 = 0, yerr1 = z->ysize, iy = 0, last_iy = -2; + y > 0; + y --) + { + if (iy != last_iy) + { + if (header.cupsBitsPerColor >= 8) + { + /* + * Do bilinear interpolation for 8+ bpp images... + */ + + if ((iy - last_iy) > 1) + ImageZoomFill(z, iy); + + ImageZoomFill(z, iy + z->yincr); + } + else + { + /* + * Just do nearest-neighbor sampling for < 8 bpp images... + */ + + ImageZoomQFill(z, iy); + } + + last_iy = iy; + } + + /* + * Format this line of raster data for the printer... + */ + + memset(row, blank, header.cupsBytesPerLine); + + r0 = z->rows[z->row]; + r1 = z->rows[1 - z->row]; + + switch (header.cupsColorSpace) + { + case CUPS_CSPACE_W : + format_W(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_RGB : + format_RGB(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_RGBA : + format_RGBA(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_K : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + format_K(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_CMY : + format_CMY(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_YMC : + format_YMC(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_CMYK : + format_CMYK(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + format_YMCK(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_KCMY : + format_KCMY(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_KCMYcm : + format_KCMYcm(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + } + + /* + * Write the raster data to the driver... + */ + + if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) < + header.cupsBytesPerLine) + { + fputs("ERROR: Unable to write raster data to driver!\n", stderr); + ImageClose(img); + exit(1); + } + + /* + * Compute the next scanline in the image... + */ + + iy += z->ystep; + yerr0 += z->ymod; + yerr1 -= z->ymod; + if (yerr1 <= 0) + { + yerr0 -= z->ysize; + yerr1 += z->ysize; + iy += z->yincr; + } + } + + /* + * Write trailing blank space as needed... + */ + + if (header.cupsHeight > z->ysize && Orientation >= 2) + { + memset(row, blank, header.cupsBytesPerLine); + + for (y = header.cupsHeight - z->ysize; y > 0; y --) + { + if (cupsRasterWritePixels(ras, row, header.cupsBytesPerLine) < + header.cupsBytesPerLine) + { + fputs("ERROR: Unable to write raster data to driver!\n", stderr); + ImageClose(img); + exit(1); + } + } + } + + /* + * Free memory used for the "zoom" engine... + */ + + ImageZoomFree(z); + } + } + + /* + * Close files... + */ + + free(row); + cupsRasterClose(ras); + ImageClose(img); + ppdClose(ppd); + + return (0); +} + + +/* + * 'exec_choice()' - Execute PostScript setpagedevice commands as appropriate. + */ + +static void +exec_choice(cups_page_header_t *header, /* I - Page header */ + ppd_choice_t *choice) /* I - Option choice to execute */ +{ + char *code, /* Pointer into code string */ + *ptr, /* Pointer into name/value string */ + name[255], /* Name of pagedevice entry */ + value[1024]; /* Value of pagedevice entry */ + + + for (code = choice->code; *code != '\0';) + { + /* + * Search for the start of a dictionary name... + */ + + while (*code != '/' && *code != '\0') + code ++; + + if (*code == '\0') + break; + + /* + * Get the name... + */ + + code ++; + for (ptr = name; isalnum(*code) && (ptr - name) < (sizeof(name) - 1);) + *ptr++ = *code++; + *ptr = '\0'; + + /* + * The parse the value as needed... + */ + + while (isspace(*code)) + code ++; + + if (*code == '\0') + break; + + if (*code == '[') + { + /* + * Read array of values... + */ + + code ++; + for (ptr = value; + *code != ']' && *code != '\0' && + (ptr - value) < (sizeof(value) - 1);) + *ptr++ = *code++; + *ptr = '\0'; + } + else if (*code == '(') + { + /* + * Read string value... + */ + + code ++; + for (ptr = value; + *code != ')' && *code != '\0' && + (ptr - value) < (sizeof(value) - 1);) + if (*code == '\\') + { + code ++; + if (isdigit(*code)) + *ptr++ = (char)strtol(code, &code, 8); + else + *ptr++ = *code++; + } + else + *ptr++ = *code++; + + *ptr = '\0'; + } + else if (isdigit(*code) || *code == '-') + { + /* + * Read single number... + */ + + for (ptr = value; + (isdigit(*code) || *code == '-') && + (ptr - value) < (sizeof(value) - 1);) + *ptr++ = *code++; + *ptr = '\0'; + } + else + continue; + + /* + * Assign the value as needed... + */ + + if (strcmp(name, "cupsMediaType") == 0) + header->cupsMediaType = atoi(value); + else if (strcmp(name, "cupsBitsPerColor") == 0) + header->cupsBitsPerColor = atoi(value); + else if (strcmp(name, "cupsColorOrder") == 0) + header->cupsColorOrder = (cups_order_t)atoi(value); + else if (strcmp(name, "cupsColorSpace") == 0) + header->cupsColorSpace = (cups_cspace_t)atoi(value); + else if (strcmp(name, "cupsCompression") == 0) + header->cupsCompression = atoi(value); + else if (strcmp(name, "cupsRowCount") == 0) + header->cupsRowCount = atoi(value); + else if (strcmp(name, "cupsRowFeed") == 0) + header->cupsRowFeed = atoi(value); + else if (strcmp(name, "cupsRowStep") == 0) + header->cupsRowStep = atoi(value); + else if (strcmp(name, "HWResolution") == 0) + sscanf(value, "%d%d", header->HWResolution + 0, header->HWResolution + 1); + else if (strcmp(name, "cupsMediaPosition") == 0) + header->MediaPosition = atoi(value); + else if (strcmp(name, "MediaType") == 0) + strcpy(header->MediaType, value); + else if (strcmp(name, "OutputType") == 0) + strcpy(header->OutputType, value); + } +} + + +/* + * 'format_CMY()' - Convert image data to CMY. + */ + +static void +format_CMY(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + *cptr, /* Pointer into cyan */ + *mptr, /* Pointer into magenta */ + *yptr, /* Pointer into yellow */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int bandwidth; /* Width of a color band */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + bandwidth = header->cupsBytesPerLine / 4; + + switch (header->cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 64 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize ; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 2; + else + { + bitmask = 64; + ptr ++; + } + } + break; + + case 2 : + dither = Floyd8x8[y & 7]; + + for (x = xsize ; x > 0; x --, r0 += 3) + { + if ((r0[0] & 63) > dither[x & 7]) + *ptr ^= (0x30 & OnPixels[r0[0]]); + else + *ptr ^= (0x30 & OffPixels[r0[0]]); + + if ((r0[1] & 63) > dither[x & 7]) + *ptr ^= (0x0c & OnPixels[r0[1]]); + else + *ptr ^= (0x0c & OffPixels[r0[1]]); + + if ((r0[2] & 63) > dither[x & 7]) + *ptr++ ^= (0x03 & OnPixels[r0[2]]); + else + *ptr++ ^= (0x03 & OffPixels[r0[2]]); + } + break; + + case 4 : + dither = Floyd4x4[y & 3]; + + for (x = xsize ; x > 0; x --, r0 += 3) + { + if ((r0[0] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[0]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[0]]); + + if ((r0[1] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[1]]); + else + *ptr ^= (0xf0 & OffPixels[r0[1]]); + + if ((r0[2] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[2]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[2]]); + } + break; + + case 8 : + for (x = xsize * 3; x > 0; x --, r0 ++, r1 ++) + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + break; + } + break; + + case CUPS_ORDER_BANDED : + cptr = ptr; + mptr = ptr + bandwidth; + yptr = ptr + 2 * bandwidth; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *cptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *mptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *yptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (r0[0] == r1[0]) + *cptr++ = r0[0]; + else + *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *mptr++ = r0[1]; + else + *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *yptr++ = r0[2]; + else + *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_PLANAR : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + switch (z) + { + case 0 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[0] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 1 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[1] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[2] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 3) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 3) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + r0 += z; + r1 += z; + + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } + break; + } +} + + +/* + * 'format_CMYK()' - Convert image data to CMYK. + */ + +static void +format_CMYK(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + *cptr, /* Pointer into cyan */ + *mptr, /* Pointer into magenta */ + *yptr, /* Pointer into yellow */ + *kptr, /* Pointer into black */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int bandwidth; /* Width of a color band */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + bandwidth = header->cupsBytesPerLine / 4; + + switch (header->cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 128 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize ; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 128; + ptr ++; + } + } + break; + + case 2 : + dither = Floyd8x8[y & 7]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if ((r0[0] & 63) > dither[x & 7]) + *ptr ^= (0xc0 & OnPixels[r0[0]]); + else + *ptr ^= (0xc0 & OffPixels[r0[0]]); + + if ((r0[1] & 63) > dither[x & 7]) + *ptr ^= (0x30 & OnPixels[r0[1]]); + else + *ptr ^= (0x30 & OffPixels[r0[1]]); + + if ((r0[2] & 63) > dither[x & 7]) + *ptr ^= (0x0c & OnPixels[r0[2]]); + else + *ptr ^= (0x0c & OffPixels[r0[2]]); + + if ((r0[3] & 63) > dither[x & 7]) + *ptr++ ^= (0x03 & OnPixels[r0[3]]); + else + *ptr++ ^= (0x03 & OffPixels[r0[3]]); + } + break; + + case 4 : + dither = Floyd4x4[y & 3]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if ((r0[0] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[0]]); + else + *ptr ^= (0xf0 & OffPixels[r0[0]]); + + if ((r0[1] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[1]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[1]]); + + if ((r0[2] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[2]]); + else + *ptr ^= (0xf0 & OffPixels[r0[2]]); + + if ((r0[3] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[3]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[3]]); + } + break; + + case 8 : + for (x = xsize * 4; x > 0; x --, r0 ++, r1 ++) + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + break; + } + break; + + case CUPS_ORDER_BANDED : + cptr = ptr; + mptr = ptr + bandwidth; + yptr = ptr + 2 * bandwidth; + kptr = ptr + 3 * bandwidth; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *cptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *mptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *yptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *kptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *kptr ^= (bitmask & OnPixels[*r0++]); + else + *kptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *kptr ^= (bitmask & OnPixels[*r0++]); + else + *kptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (r0[0] == r1[0]) + *cptr++ = r0[0]; + else + *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *mptr++ = r0[1]; + else + *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *yptr++ = r0[2]; + else + *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + + if (r0[3] == r1[3]) + *kptr++ = r0[3]; + else + *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_PLANAR : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if (*r0 > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + r0 += z; + r1 += z; + + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } + break; + } +} + + +/* + * 'format_K()' - Convert image data to black. + */ + +static void +format_K(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0++]); + else + *ptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0++]); + else + *ptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 ++, r1 ++) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } +} + + +/* + * 'format_KCMY()' - Convert image data to KCMY. + */ + +static void +format_KCMY(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + *cptr, /* Pointer into cyan */ + *mptr, /* Pointer into magenta */ + *yptr, /* Pointer into yellow */ + *kptr, /* Pointer into black */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int bandwidth; /* Width of a color band */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + bandwidth = header->cupsBytesPerLine / 4; + + switch (header->cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 128 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if (r0[3] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[0] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[1] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[2] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 128; + ptr ++; + } + } + break; + + case 2 : + dither = Floyd8x8[y & 7]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if ((r0[3] & 63) > dither[x & 7]) + *ptr ^= (0xc0 & OnPixels[r0[3]]); + else + *ptr ^= (0xc0 & OffPixels[r0[3]]); + + if ((r0[0] & 63) > dither[x & 7]) + *ptr ^= (0x30 & OnPixels[r0[0]]); + else + *ptr ^= (0x30 & OffPixels[r0[0]]); + + if ((r0[1] & 63) > dither[x & 7]) + *ptr ^= (0x0c & OnPixels[r0[1]]); + else + *ptr ^= (0x0c & OffPixels[r0[1]]); + + if ((r0[2] & 63) > dither[x & 7]) + *ptr++ ^= (0x03 & OnPixels[r0[2]]); + else + *ptr++ ^= (0x03 & OffPixels[r0[2]]); + } + break; + + case 4 : + dither = Floyd4x4[y & 3]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if ((r0[3] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[3]]); + else + *ptr ^= (0xf0 & OffPixels[r0[3]]); + + if ((r0[0] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[0]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[0]]); + + if ((r0[1] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[1]]); + else + *ptr ^= (0xf0 & OffPixels[r0[1]]); + + if ((r0[2] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[2]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[2]]); + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (r0[3] == r1[3]) + *ptr++ = r0[3]; + else + *ptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; + + if (r0[0] == r1[0]) + *ptr++ = r0[0]; + else + *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *ptr++ = r0[1]; + else + *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *ptr++ = r0[2]; + else + *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_BANDED : + kptr = ptr; + cptr = ptr + bandwidth; + mptr = ptr + 2 * bandwidth; + yptr = ptr + 3 * bandwidth; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *cptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *mptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *yptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *kptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *kptr ^= (bitmask & OnPixels[*r0++]); + else + *kptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *kptr ^= (bitmask & OnPixels[*r0++]); + else + *kptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (r0[0] == r1[0]) + *cptr++ = r0[0]; + else + *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *mptr++ = r0[1]; + else + *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *yptr++ = r0[2]; + else + *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + + if (r0[3] == r1[3]) + *kptr++ = r0[3]; + else + *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_PLANAR : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + if (z == 0) + r0 += 3; + else + r0 += z - 1; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if (*r0 > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + if (z == 0) + r0 += 3; + else + r0 += z - 1; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + if (z == 0) + r0 += 3; + else + r0 += z - 1; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + if (z == 0) + { + r0 += 3; + r1 += 3; + } + else + { + r0 += z - 1; + r1 += z - 1; + } + + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } + break; + } +} + + +/* + * 'format_KCMYcm()' - Convert image data to KCMYcm. + */ + +static void +format_KCMYcm(cups_page_header_t *header,/* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + int pc, pm, py, pk; /* Cyan, magenta, yellow, and black values */ + ib_t *ptr, /* Pointer into row */ + *cptr, /* Pointer into cyan */ + *mptr, /* Pointer into magenta */ + *yptr, /* Pointer into yellow */ + *kptr, /* Pointer into black */ + *lcptr, /* Pointer into light cyan */ + *lmptr, /* Pointer into light magenta */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int bandwidth; /* Width of a color band */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + if (header->cupsBitsPerColor == 1) + bandwidth = header->cupsBytesPerLine / 6; + else + bandwidth = header->cupsBytesPerLine / 4; + + switch (header->cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + switch (header->cupsBitsPerColor) + { + case 1 : + dither = Floyd16x16[y & 15]; + + for (x = xsize ; x > 0; x --) + { + pc = *r0++ > dither[x & 15]; + pm = *r0++ > dither[x & 15]; + py = *r0++ > dither[x & 15]; + pk = *r0++ > dither[x & 15]; + + if (pk) + *ptr++ ^= 32; /* Black */ + else if (pc && pm) + *ptr++ ^= 17; /* Blue (cyan + light magenta) */ + else if (pc && py) + *ptr++ ^= 6; /* Green (light cyan + yellow) */ + else if (pm && py) + *ptr++ ^= 12; /* Red (magenta + yellow) */ + else if (pc) + *ptr++ ^= 16; + else if (pm) + *ptr++ ^= 8; + else if (py) + *ptr++ ^= 4; + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (r0[3] == r1[3]) + *ptr++ = r0[3]; + else + *ptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; + + if (r0[0] == r1[0]) + *ptr++ = r0[0]; + else + *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *ptr++ = r0[1]; + else + *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *ptr++ = r0[2]; + else + *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_BANDED : + kptr = ptr; + cptr = ptr + bandwidth; + mptr = ptr + 2 * bandwidth; + yptr = ptr + 3 * bandwidth; + lcptr = ptr + 4 * bandwidth; + lmptr = ptr + 5 * bandwidth; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + pc = *r0++ > dither[x & 15]; + pm = *r0++ > dither[x & 15]; + py = *r0++ > dither[x & 15]; + pk = *r0++ > dither[x & 15]; + + if (pk) + *kptr ^= bitmask; /* Black */ + else if (pc && pm) + { + *cptr ^= bitmask; /* Blue (cyan + light magenta) */ + *lmptr ^= bitmask; + } + else if (pc && py) + { + *lcptr ^= bitmask; /* Green (light cyan + yellow) */ + *yptr ^= bitmask; + } + else if (pm && py) + { + *mptr ^= bitmask; /* Red (magenta + yellow) */ + *yptr ^= bitmask; + } + else if (pc) + *cptr ^= bitmask; + else if (pm) + *mptr ^= bitmask; + else if (py) + *yptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + cptr ++; + mptr ++; + yptr ++; + kptr ++; + lcptr ++; + lmptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (r0[0] == r1[0]) + *cptr++ = r0[0]; + else + *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *mptr++ = r0[1]; + else + *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *yptr++ = r0[2]; + else + *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + + if (r0[3] == r1[3]) + *kptr++ = r0[3]; + else + *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_PLANAR : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + switch (z) + { + case 0 : + for (x = xsize; x > 0; x --, r0 += 4) + { + if (r0[3] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 1 : + for (x = xsize; x > 0; x --, r0 += 4) + { + if (r0[0] > dither[x & 15] && + r0[2] < dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + for (x = xsize; x > 0; x --, r0 += 4) + { + if (r0[1] > dither[x & 15] && + (r0[0] < dither[x & 15] || + r0[2] > dither[x & 15])) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 3 : + for (x = xsize; x > 0; x --, r0 += 4) + { + if (r0[2] > dither[x & 15] && + (r0[0] < dither[x & 15] || + r0[1] < dither[x & 15])) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 4 : + for (x = xsize; x > 0; x --, r0 += 4) + { + if (r0[0] > dither[x & 15] && + r0[2] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 5 : + for (x = xsize; x > 0; x --, r0 += 4) + { + if (r0[0] > dither[x & 15] && + r0[1] > dither[x & 15] && + r0[2] < dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + } + break; + + case 8 : + if (z == 0) + { + r0 += 3; + r1 += 3; + } + else + { + r0 += z - 1; + r1 += z - 1; + } + + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } + break; + } +} + + +/* + * 'format_RGBA()' - Convert image data to RGBA. + */ + +static void +format_RGBA(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + *cptr, /* Pointer into cyan */ + *mptr, /* Pointer into magenta */ + *yptr, /* Pointer into yellow */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int bandwidth; /* Width of a color band */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + bandwidth = header->cupsBytesPerLine / 4; + + switch (header->cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 128 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize ; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 2) + { + *ptr ^= 16; + bitmask >>= 2; + } + else + { + bitmask = 128; + *ptr++ ^= 1; + } + } + break; + + case 2 : + dither = Floyd8x8[y & 7]; + + for (x = xsize ; x > 0; x --, r0 += 3) + { + if ((r0[0] & 63) > dither[x & 7]) + *ptr ^= (0xc0 & OnPixels[r0[0]]); + else + *ptr ^= (0xc0 & OffPixels[r0[0]]); + + if ((r0[1] & 63) > dither[x & 7]) + *ptr ^= (0x30 & OnPixels[r0[1]]); + else + *ptr ^= (0x30 & OffPixels[r0[1]]); + + if ((r0[2] & 63) > dither[x & 7]) + *ptr ^= (0x0c & OnPixels[r0[2]]); + else + *ptr ^= (0x0c & OffPixels[r0[2]]); + + *ptr++ ^= 0x03; + } + break; + + case 4 : + dither = Floyd4x4[y & 3]; + + for (x = xsize ; x > 0; x --, r0 += 3) + { + if ((r0[0] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[0]]); + else + *ptr ^= (0xf0 & OffPixels[r0[0]]); + + if ((r0[1] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[1]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[1]]); + + if ((r0[2] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[2]]); + else + *ptr ^= (0xf0 & OffPixels[r0[2]]); + + *ptr++ ^= 0x0f; + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (r0[0] == r1[0]) + *ptr++ = r0[0]; + else + *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *ptr++ = r0[1]; + else + *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *ptr++ = r0[2]; + else + *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + + *ptr++ = 255; + } + break; + } + break; + + case CUPS_ORDER_BANDED : + cptr = ptr; + mptr = ptr + bandwidth; + yptr = ptr + 2 * bandwidth; + + memset(ptr + 3 * bandwidth, 255, bandwidth); + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *cptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *mptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *yptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (r0[0] == r1[0]) + *cptr++ = r0[0]; + else + *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *mptr++ = r0[1]; + else + *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *yptr++ = r0[2]; + else + *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_PLANAR : + if (z == 3) + { + memset(row, 255, header->cupsBytesPerLine); + break; + } + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + switch (z) + { + case 0 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[0] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 1 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[1] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[2] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 3) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 3) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + r0 += z; + r1 += z; + + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } + break; + } +} + + +/* + * 'format_W()' - Convert image data to luminance. + */ + +static void +format_W(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0++]); + else + *ptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0++]); + else + *ptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 ++, r1 ++) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } +} + + +/* + * 'format_YMC()' - Convert image data to YMC. + */ + +static void +format_YMC(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + *cptr, /* Pointer into cyan */ + *mptr, /* Pointer into magenta */ + *yptr, /* Pointer into yellow */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int bandwidth; /* Width of a color band */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + bandwidth = header->cupsBytesPerLine / 4; + + switch (header->cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 64 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize ; x > 0; x --, r0 += 3) + { + if (r0[2] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[1] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[0] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 2; + else + { + bitmask = 64; + ptr ++; + } + } + break; + + case 2 : + dither = Floyd8x8[y & 7]; + + for (x = xsize ; x > 0; x --, r0 += 3) + { + if ((r0[2] & 63) > dither[x & 7]) + *ptr ^= (0x30 & OnPixels[r0[2]]); + else + *ptr ^= (0x30 & OffPixels[r0[2]]); + + if ((r0[1] & 63) > dither[x & 7]) + *ptr ^= (0x0c & OnPixels[r0[1]]); + else + *ptr ^= (0x0c & OffPixels[r0[1]]); + + if ((r0[0] & 63) > dither[x & 7]) + *ptr++ ^= (0x03 & OnPixels[r0[0]]); + else + *ptr++ ^= (0x03 & OffPixels[r0[0]]); + } + break; + + case 4 : + dither = Floyd4x4[y & 3]; + + for (x = xsize ; x > 0; x --, r0 += 3) + { + if ((r0[2] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[2]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[2]]); + + if ((r0[1] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[1]]); + else + *ptr ^= (0xf0 & OffPixels[r0[1]]); + + if ((r0[0] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[0]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[0]]); + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (r0[2] == r1[2]) + *ptr++ = r0[2]; + else + *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *ptr++ = r0[1]; + else + *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[0] == r1[0]) + *ptr++ = r0[0]; + else + *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_BANDED : + yptr = ptr; + mptr = ptr + bandwidth; + cptr = ptr + 2 * bandwidth; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *cptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *mptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *yptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + cptr ++; + mptr ++; + yptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (r0[0] == r1[0]) + *cptr++ = r0[0]; + else + *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *mptr++ = r0[1]; + else + *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *yptr++ = r0[2]; + else + *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_PLANAR : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + switch (z) + { + case 2 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[0] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 1 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[1] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 0 : + for (x = xsize; x > 0; x --, r0 += 3) + { + if (r0[2] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + z = 2 - z; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 3) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + z = 2 - z; + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 3) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + z = 2 - z; + r0 += z; + r1 += z; + + for (x = xsize; x > 0; x --, r0 += 3, r1 += 3) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } + break; + } +} + + +/* + * 'format_YMCK()' - Convert image data to YMCK. + */ + +static void +format_YMCK(cups_page_header_t *header, /* I - Page header */ + unsigned char *row, /* IO - Bitmap data for device */ + int y, /* I - Current row */ + int z, /* I - Current plane */ + int xsize, /* I - Width of image data */ + int ysize, /* I - Height of image data */ + int yerr0, /* I - Top Y error */ + int yerr1, /* I - Bottom Y error */ + ib_t *r0, /* I - Primary image data */ + ib_t *r1) /* I - Image data for interpolation */ +{ + ib_t *ptr, /* Pointer into row */ + *cptr, /* Pointer into cyan */ + *mptr, /* Pointer into magenta */ + *yptr, /* Pointer into yellow */ + *kptr, /* Pointer into black */ + bitmask; /* Current mask for pixel */ + int bitoffset; /* Current offset in line */ + int bandwidth; /* Width of a color band */ + int x, /* Current X coordinate on page */ + *dither; /* Pointer into dither array */ + + + if (Orientation == 1 || Orientation == 2) + bitoffset = header->cupsBitsPerPixel * (header->cupsWidth - xsize); + else + bitoffset = 0; + + ptr = row + bitoffset / 8; + bandwidth = header->cupsBytesPerLine / 4; + + switch (header->cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 128 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if (r0[2] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[1] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[0] > dither[x & 15]) + *ptr ^= bitmask; + bitmask >>= 1; + + if (r0[3] > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 128; + + ptr ++; + } + } + break; + + case 2 : + dither = Floyd8x8[y & 7]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if ((r0[2] & 63) > dither[x & 7]) + *ptr ^= (0xc0 & OnPixels[r0[2]]); + else + *ptr ^= (0xc0 & OffPixels[r0[2]]); + + if ((r0[1] & 63) > dither[x & 7]) + *ptr ^= (0x30 & OnPixels[r0[1]]); + else + *ptr ^= (0x30 & OffPixels[r0[1]]); + + if ((r0[0] & 63) > dither[x & 7]) + *ptr ^= (0x0c & OnPixels[r0[0]]); + else + *ptr ^= (0x0c & OffPixels[r0[0]]); + + if ((r0[3] & 63) > dither[x & 7]) + *ptr++ ^= (0x03 & OnPixels[r0[3]]); + else + *ptr++ ^= (0x03 & OffPixels[r0[3]]); + } + break; + + case 4 : + dither = Floyd4x4[y & 3]; + + for (x = xsize ; x > 0; x --, r0 += 4) + { + if ((r0[2] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[2]]); + else + *ptr ^= (0xf0 & OffPixels[r0[2]]); + + if ((r0[1] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[1]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[1]]); + + if ((r0[0] & 15) > dither[x & 3]) + *ptr ^= (0xf0 & OnPixels[r0[0]]); + else + *ptr ^= (0xf0 & OffPixels[r0[0]]); + + if ((r0[3] & 15) > dither[x & 3]) + *ptr++ ^= (0x0f & OnPixels[r0[3]]); + else + *ptr++ ^= (0x0f & OffPixels[r0[3]]); + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (r0[2] == r1[2]) + *ptr++ = r0[2]; + else + *ptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *ptr++ = r0[1]; + else + *ptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[0] == r1[0]) + *ptr++ = r0[0]; + else + *ptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[3] == r1[3]) + *ptr++ = r0[3]; + else + *ptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_BANDED : + yptr = ptr; + mptr = ptr + bandwidth; + cptr = ptr + 2 * bandwidth; + kptr = ptr + 3 * bandwidth; + + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + for (x = xsize; x > 0; x --) + { + if (*r0++ > dither[x & 15]) + *cptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *mptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *yptr ^= bitmask; + if (*r0++ > dither[x & 15]) + *kptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 63) > dither[x & 7]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 63) > dither[x & 7]) + *kptr ^= (bitmask & OnPixels[*r0++]); + else + *kptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + + for (x = xsize; x > 0; x --) + { + if ((*r0 & 15) > dither[x & 3]) + *cptr ^= (bitmask & OnPixels[*r0++]); + else + *cptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *mptr ^= (bitmask & OnPixels[*r0++]); + else + *mptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *yptr ^= (bitmask & OnPixels[*r0++]); + else + *yptr ^= (bitmask & OffPixels[*r0++]); + + if ((*r0 & 15) > dither[x & 3]) + *kptr ^= (bitmask & OnPixels[*r0++]); + else + *kptr ^= (bitmask & OffPixels[*r0++]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + cptr ++; + mptr ++; + yptr ++; + kptr ++; + } + } + break; + + case 8 : + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (r0[0] == r1[0]) + *cptr++ = r0[0]; + else + *cptr++ = (r0[0] * yerr0 + r1[0] * yerr1) / ysize; + + if (r0[1] == r1[1]) + *mptr++ = r0[1]; + else + *mptr++ = (r0[1] * yerr0 + r1[1] * yerr1) / ysize; + + if (r0[2] == r1[2]) + *yptr++ = r0[2]; + else + *yptr++ = (r0[2] * yerr0 + r1[2] * yerr1) / ysize; + + if (r0[3] == r1[3]) + *kptr++ = r0[3]; + else + *kptr++ = (r0[3] * yerr0 + r1[3] * yerr1) / ysize; + } + break; + } + break; + + case CUPS_ORDER_PLANAR : + switch (header->cupsBitsPerColor) + { + case 1 : + bitmask = 0x80 >> (bitoffset & 7); + dither = Floyd16x16[y & 15]; + + if (z < 3) + r0 += 2 - z; + else + r0 += z; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if (*r0 > dither[x & 15]) + *ptr ^= bitmask; + + if (bitmask > 1) + bitmask >>= 1; + else + { + bitmask = 0x80; + ptr ++; + } + } + break; + + case 2 : + bitmask = 0xc0 >> (bitoffset & 7); + dither = Floyd8x8[y & 7]; + if (z == 3) + r0 += 3; + else + r0 += 2 - z; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if ((*r0 & 63) > dither[x & 7]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask > 3) + bitmask >>= 2; + else + { + bitmask = 0xc0; + + ptr ++; + } + } + break; + + case 4 : + bitmask = 0xf0 >> (bitoffset & 7); + dither = Floyd4x4[y & 3]; + if (z == 3) + r0 += 3; + else + r0 += 2 - z; + + for (x = xsize; x > 0; x --, r0 += 4) + { + if ((*r0 & 15) > dither[x & 3]) + *ptr ^= (bitmask & OnPixels[*r0]); + else + *ptr ^= (bitmask & OffPixels[*r0]); + + if (bitmask == 0xf0) + bitmask = 0x0f; + else + { + bitmask = 0xf0; + + ptr ++; + } + } + break; + + case 8 : + if (z == 3) + { + r0 += 3; + r1 += 3; + } + else + { + r0 += 2 - z; + r1 += 2 - z; + } + + for (x = xsize; x > 0; x --, r0 += 4, r1 += 4) + { + if (*r0 == *r1) + *ptr++ = *r0; + else + *ptr++ = (*r0 * yerr0 + *r1 * yerr1) / ysize; + } + break; + } + break; + } +} + + +/* + * 'make_lut()' - Make a lookup table given gamma and brightness values. + */ + +static void +make_lut(ib_t *lut, /* I - Lookup table */ + int colorspace, /* I - Colorspace */ + float g, /* I - Image gamma */ + float b) /* I - Image brightness */ +{ + int i; /* Looping var */ + int v; /* Current value */ + + + g = 1.0 / g; + b = 1.0 / b; + + for (i = 0; i < 256; i ++) + { + if (colorspace < 0) + v = 255.0 * b * (1.0 - pow(1.0 - (float)i / 255.0, g)) + 0.5; + else + v = 255.0 * (1.0 - b * (1.0 - pow((float)i / 255.0, g))) + 0.5; + + if (v < 0) + *lut++ = 0; + else if (v > 255) + *lut++ = 255; + else + *lut++ = v; + } +} + + +/* + * End of "$Id$". + */ diff --git a/filter/pstops.c b/filter/pstops.c new file mode 100644 index 0000000000..f93d76f26a --- /dev/null +++ b/filter/pstops.c @@ -0,0 +1,804 @@ +/* + * "$Id$" + * + * PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry... + * check_range() - Check to see if the current page is selected for + * copy_bytes() - Copy bytes from the input file to stdout... + * end_nup() - End processing for N-up printing... + * psgets() - Get a line from a file. + * start_nup() - Start processing for N-up printing... + */ + +/* + * Include necessary headers... + */ + +#include "common.h" + + +/* + * Constants... + */ + +#define MAX_PAGES 10000 + + +/* + * Globals... + */ + +int NumPages = 0; /* Number of pages in file */ +long Pages[MAX_PAGES]; /* Offsets to each page */ +char PageLabels[MAX_PAGES][64]; + /* Page labels */ +const char *PageRanges = NULL; /* Range of pages selected */ +const char *PageSet = NULL; /* All, Even, Odd pages */ +int Order = 0, /* 0 = normal, 1 = reverse pages */ + Flip = 0, /* Flip/mirror pages */ + NUp = 1, /* Number of pages on each sheet (1, 2, 4) */ + Collate = 0, /* Collate copies? */ + Copies = 1; /* Number of copies */ + + +/* + * Local functions... + */ + +static int check_range(int page); +static void copy_bytes(FILE *fp, size_t length); +static void end_nup(int number); +static char *psgets(char *buf, size_t len, FILE *fp); +static void start_nup(int number); + + +/* + * 'main()' - Main entry... + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + FILE *fp; /* Print file */ + ppd_file_t *ppd; /* PPD file */ + int num_options; /* Number of print options */ + cups_option_t *options; /* Print options */ + const char *val; /* Option value */ + char tempfile[255]; /* Temporary file name */ + FILE *temp; /* Temporary file */ + int number; /* Page number */ + int slowcollate; /* 1 if we need to collate manually */ + int sloworder; /* 1 if we need to order manually */ + char line[8192]; /* Line buffer */ + float g; /* Gamma correction value */ + float b; /* Brightness factor */ + int level; /* Nesting level for embedded files */ + int nbytes, /* Number of bytes read */ + tbytes; /* Total bytes to read for binary data */ + int page; /* Current page sequence number */ + + + if (argc < 6 || argc > 7) + { + fputs("ERROR: pstops job-id user title copies options [file]\n", stderr); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + fp = stdin; + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file - "); + return (1); + } + } + + /* + * Process command-line options and write the prolog... + */ + + g = 1.0; + b = 1.0; + + Copies = atoi(argv[4]); + + ppd = ppdOpenFile(getenv("PPD")); + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + ppd = SetCommonOptions(num_options, options, 1); + + ppdMarkDefaults(ppd); + cupsMarkOptions(ppd, num_options, options); + + if ((val = cupsGetOption("page-ranges", num_options, options)) != NULL) + PageRanges = val; + + if ((val = cupsGetOption("page-set", num_options, options)) != NULL) + PageSet = val; + + if ((val = cupsGetOption("multiple-document-handling", num_options, options)) != NULL) + { + /* + * This IPP attribute is unnecessarily complicated... + * + * single-document, separate-documents-collated-copies, and + * single-document-new-sheet all require collated copies. + * + * separate-documents-collated-copies allows for uncollated copies. + */ + + Collate = strcmp(val, "separate-documents-collated-copies") != 0; + } + + if ((val = cupsGetOption("Collate", num_options, options)) != NULL && + strcmp(val, "True") == 0) + Collate = 1; + + if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL && + strcmp(val, "Reverse") == 0) + Order = 1; + + if ((val = cupsGetOption("number-up", num_options, options)) != NULL) + NUp = atoi(val); + + if ((val = cupsGetOption("gamma", num_options, options)) != NULL) + g = atoi(val) * 0.001f; + + if ((val = cupsGetOption("brightness", num_options, options)) != NULL) + b = atoi(val) * 0.01f; + + /* + * See if we have to filter the fast or slow way... + */ + + if (ppdFindOption(ppd, "Collate") == NULL && Collate && Copies > 1) + slowcollate = 1; + else + slowcollate = 0; + + if (ppdFindOption(ppd, "OutputOrder") == NULL && Order) + sloworder = 1; + else + sloworder = 0; + + /* + * If we need to filter slowly, then create a temporary file for page data... + * + * If the temp file can't be created, then we'll ignore the collating/output + * order options... + */ + + if (sloworder || slowcollate) + { + temp = fopen(cupsTempFile(tempfile, sizeof(tempfile)), "wb+"); + + if (temp == NULL) + slowcollate = sloworder = 0; + } + + /* + * Write any "exit server" options that have been selected... + */ + + ppdEmit(ppd, stdout, PPD_ORDER_EXIT); + + /* + * Write any JCL commands that are needed to print PostScript code... + */ + + if (ppd != NULL && ppd->jcl_begin && ppd->jcl_ps) + { + fputs(ppd->jcl_begin, stdout); + ppdEmit(ppd, stdout, PPD_ORDER_JCL); + fputs(ppd->jcl_ps, stdout); + } + + /* + * Read the first line to see if we have DSC comments... + */ + + if (psgets(line, sizeof(line), fp) == NULL) + { + fputs("ERROR: Empty print file!\n", stderr); + ppdClose(ppd); + return (1); + } + + /* + * Start sending the document with any commands needed... + */ + + puts(line); + + if (ppd != NULL && ppd->patches != NULL) + puts(ppd->patches); + + ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT); + ppdEmit(ppd, stdout, PPD_ORDER_ANY); + ppdEmit(ppd, stdout, PPD_ORDER_PROLOG); + + if (NUp > 1) + puts("userdict begin\n" + "/ESPshowpage /showpage load def\n" + "/showpage { } def\n" + "end"); + + if (g != 1.0 || b != 1.0) + printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } " + "ifelse %.3f mul } bind settransfer\n", g, b); + + if (Copies > 1 && (!Collate || !slowcollate)) + printf("/#copies %d def\n", Copies); + + if (strncmp(line, "%!PS-Adobe-", 11) == 0) + { + /* + * OK, we have DSC comments; read until we find a %%Page comment... + */ + + level = 0; + + while (psgets(line, sizeof(line), fp) != NULL) + if (strncmp(line, "%%BeginDocument:", 16) == 0 || + strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */ + level ++; + else if (strcmp(line, "%%EndDocument") == 0 && level > 0) + level --; + else if (strncmp(line, "%%Page:", 7) == 0 && level == 0) + break; + else if (strncmp(line, "%%BeginBinary:", 14) == 0 || + (strncmp(line, "%%BeginData:", 12) == 0 && + strstr(line, "Binary") != NULL)) + { + /* + * Copy binary data... + */ + + tbytes = atoi(strchr(line, ':') + 1); + while (tbytes > 0) + { + nbytes = fread(line, 1, sizeof(line), fp); + fwrite(line, 1, nbytes, stdout); + tbytes -= nbytes; + } + } + else + puts(line); + + /* + * Then read all of the pages, filtering as needed... + */ + + for (page = 1;;) + { + if (strncmp(line, "%%BeginDocument:", 16) == 0 || + strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */ + level ++; + else if (strcmp(line, "%%EndDocument") == 0 && level > 0) + level --; + else if (strncmp(line, "%%Page:", 7) == 0 && level == 0) + { + if (sscanf(line, "%*s%*s%d", &number) == 1) + { + if (!check_range(number)) + { + while (psgets(line, sizeof(line), fp) != NULL) + if (strncmp(line, "%%BeginDocument:", 16) == 0 || + strncmp(line, "%%BeginDocument ", 16) == 0) /* Adobe Acrobat BUG */ + level ++; + else if (strcmp(line, "%%EndDocument") == 0 && level > 0) + level --; + else if (strncmp(line, "%%Page:", 7) == 0 && level == 0) + break; + + continue; + } + + if (!sloworder && NumPages > 0) + end_nup(NumPages - 1); + + if (slowcollate || sloworder) + Pages[NumPages] = ftell(temp); + + if (!sloworder) + { + if ((NumPages % NUp) == 0) + { + if (ppd == NULL || ppd->num_filters == 0) + fprintf(stderr, "PAGE: %d %d\n", page, Copies); + + printf("%%%%Page: %d %d\n", page, page); + page ++; + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + } + + start_nup(NumPages); + } + + NumPages ++; + } + } + else if (strncmp(line, "%%BeginBinary:", 14) == 0 || + (strncmp(line, "%%BeginData:", 12) == 0 && + strstr(line, "Binary") != NULL)) + { + /* + * Copy binary data... + */ + + tbytes = atoi(strchr(line, ':') + 1); + while (tbytes > 0) + { + nbytes = fread(line, 1, sizeof(line), fp); + + if (!sloworder) + fwrite(line, 1, nbytes, stdout); + + if (slowcollate || sloworder) + fwrite(line, 1, nbytes, stdout); + + tbytes -= nbytes; + } + } + else + { + if (!sloworder) + puts(line); + + if (slowcollate || sloworder) + { + fputs(line, temp); + putc('\n', temp); + } + } + + if (psgets(line, sizeof(line), fp) == NULL) + break; + } + + if (!sloworder) + end_nup((NumPages + NUp - 1) & (NUp - 1)); + + if (slowcollate || sloworder) + { + Pages[NumPages] = ftell(temp); + page = 1; + + if (!sloworder) + { + while (Copies > 0) + { + rewind(temp); + + for (number = 0; number < NumPages; number ++) + { + if ((number % NUp) == 0) + { + if (ppd == NULL || ppd->num_filters == 0) + fprintf(stderr, "PAGE: %d 1\n", page); + + printf("%%%%Page: %d %d\n", page, page); + page ++; + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + } + + start_nup(number); + copy_bytes(temp, Pages[number + 1] - Pages[number]); + end_nup(number); + } + + Copies --; + } + } + else + { + do + { + for (number = NumPages - 1; number >= 0; number --) + { + if ((number % NUp) == 0) + { + if (ppd == NULL || ppd->num_filters == 0) + fprintf(stderr, "PAGE: %d %d\n", page, + slowcollate ? 1 : Copies); + + printf("%%%%Page: %d %d\n", page, page); + page ++; + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + } + + start_nup(NumPages - 1 - number); + fseek(temp, Pages[number], SEEK_SET); + copy_bytes(temp, Pages[number + 1] - Pages[number]); + end_nup(NumPages - 1 - number); + } + + Copies --; + } + while (Copies > 0 || !slowcollate); + } + } + } + else + { + /* + * No DSC comments - write any page commands and then the rest of the file... + */ + + if (ppd == NULL || ppd->num_filters == 0) + fprintf(stderr, "PAGE: 1 %d\n", slowcollate ? 1 : Copies); + + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + + while (psgets(line, sizeof(line), fp) != NULL) + { + puts(line); + + if (slowcollate) + { + fputs(line, temp); + putc('\n', temp); + } + } + + if (slowcollate) + { + while (Copies > 1) + { + if (ppd == NULL || ppd->num_filters == 0) + fputs("PAGE: 1 1\n", stderr); + + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + rewind(temp); + copy_bytes(temp, 0); + } + } + } + + /* + * End the job with the appropriate JCL command or CTRL-D otherwise. + */ + + if (ppd != NULL && ppd->jcl_end) + fputs(ppd->jcl_end, stdout); + else + putchar(0x04); + + /* + * Close files and remove the temporary file if needed... + */ + + if (slowcollate || sloworder) + { + fclose(temp); + unlink(tempfile); + } + + ppdClose(ppd); + + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * 'check_range()' - Check to see if the current page is selected for + * printing. + */ + +static int /* O - 1 if selected, 0 otherwise */ +check_range(int page) /* I - Page number */ +{ + const char *range; /* Pointer into range string */ + int lower, upper; /* Lower and upper page numbers */ + + + if (PageSet != NULL) + { + /* + * See if we only print even or odd pages... + */ + + if (strcmp(PageSet, "even") == 0 && (page & 1)) + return (0); + if (strcmp(PageSet, "odd") == 0 && !(page & 1)) + return (0); + } + + if (PageRanges == NULL) + return (1); /* No range, print all pages... */ + + for (range = PageRanges; *range != '\0';) + { + if (*range == '-') + { + lower = 1; + range ++; + upper = strtol(range, (char **)&range, 10); + } + else + { + lower = strtol(range, (char **)&range, 10); + + if (*range == '-') + { + range ++; + if (!isdigit(*range)) + upper = 65535; + else + upper = strtol(range, (char **)&range, 10); + } + else + upper = lower; + } + + if (page >= lower && page <= upper) + return (1); + + if (*range == ',') + range ++; + else + break; + } + + return (0); +} + + +/* + * 'copy_bytes()' - Copy bytes from the input file to stdout... + */ + +static void +copy_bytes(FILE *fp, /* I - File to read from */ + size_t length) /* I - Length of page data */ +{ + char buffer[8192]; /* Data buffer */ + size_t nbytes, /* Number of bytes read */ + nleft; /* Number of bytes left/remaining */ + + + nleft = length; + + while (nleft > 0 || length == 0) + { + if ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) < 1) + return; + + nleft -= nbytes; + + fwrite(buffer, 1, nbytes, stdout); + } +} + + +/* + * 'end_nup()' - End processing for N-up printing... + */ + +static void +end_nup(int number) /* I - Page number */ +{ + if (Flip || Orientation || NUp > 1) + puts("grestoreall"); + + switch (NUp) + { + case 2 : + if ((number & 1) == 1) + puts("ESPshowpage"); + break; + + case 4 : + if ((number & 3) == 3) + puts("ESPshowpage"); + break; + } +} + + +/* + * 'psgets()' - Get a line from a file. + * + * Note: + * + * This function differs from the gets() function in that it + * handles any combination of CR, LF, or CR LF to end input + * lines. + */ + +static char * /* O - String or NULL if EOF */ +psgets(char *buf, /* I - Buffer to read into */ + size_t len, /* I - Length of buffer */ + FILE *fp) /* I - File to read from */ +{ + char *bufptr; /* Pointer into buffer */ + int ch; /* Character from file */ + + + len --; + bufptr = buf; + + while ((bufptr - buf) < len) + { + if ((ch = getc(fp)) == EOF) + break; + + if (ch == 0x0d) + { + /* + * Got a CR; see if there is a LF as well... + */ + + ch = getc(fp); + if (ch != EOF && ch != 0x0a) + ungetc(ch, fp); /* Nope, save it for later... */ + + break; + } + else if (ch == 0x0a) + break; + else + *bufptr++ = ch; + } + + /* + * Nul-terminate the string and return it (or NULL for EOF). + */ + + *bufptr = '\0'; + + if (ch == EOF && bufptr == buf) + return (NULL); + else + return (buf); +} + + +/* + * 'start_nup()' - Start processing for N-up printing... + */ + +static void +start_nup(int number) /* I - Page number */ +{ + int x, y; /* Relative position of subpage */ + float w, l, /* Width and length of subpage */ + tx, ty; /* Translation values for subpage */ + + + if (Flip || Orientation || NUp > 1) + puts("gsave"); + + if (Flip) + printf("%.0f 0 translate -1 1 scale\n", PageWidth); + + switch (Orientation) + { + case 1 : /* Landscape */ + printf("%.0f 0 translate 90 rotate\n", PageLength); + break; + case 2 : /* Reverse Portrait */ + printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); + break; + case 3 : /* Reverse Landscape */ + printf("0 %.0f translate -90 rotate\n", PageWidth); + break; + } + + switch (NUp) + { + case 2 : + x = number & 1; + + if (Orientation & 1) + { + x = 1 - x; + w = PageLength; + l = w * PageLength / PageWidth; + + if (l > (PageWidth * 0.5)) + { + l = PageWidth * 0.5; + w = l * PageWidth / PageLength; + } + + tx = PageWidth * 0.5 - l; + ty = (PageLength - w) * 0.5; + } + else + { + l = PageWidth; + w = l * PageWidth / PageLength; + + if (w > (PageLength * 0.5)) + { + w = PageLength * 0.5; + l = w * PageLength / PageWidth; + } + + tx = PageLength * 0.5 - w; + ty = (PageWidth - l) * 0.5; + } + + if (Orientation & 1) + { + printf("0 %.0f translate -90 rotate\n", PageLength); + printf("%.0f %.0f translate %.3f %.3f scale\n", + ty, tx + l * x, w / PageWidth, l / PageLength); + } + else + { + printf("%.0f 0 translate 90 rotate\n", PageWidth); + printf("%.0f %.0f translate %.3f %.3f scale\n", + tx + w * x, ty, w / PageWidth, l / PageLength); + } + + printf("newpath\n" + "0 0 moveto\n" + "%.0f 0 lineto\n" + "%.0f %.0f lineto\n" + "0 %.0f lineto\n" + "closepath clip newpath\n", + PageWidth, PageWidth, PageLength, PageLength); + break; + + case 4 : + x = number & 1; + y = 1 - ((number & 2) != 0); + w = PageWidth * 0.5; + l = PageLength * 0.5; + + printf("%.0f %.0f translate 0.5 0.5 scale\n", x * w, y * l); + printf("newpath\n" + "0 0 moveto\n" + "%.0f 0 lineto\n" + "%.0f %.0f lineto\n" + "0 %.0f lineto\n" + "closepath clip newpath\n", + PageWidth, PageWidth, PageLength, PageLength); + break; + } +} + + +/* + * End of "$Id$". + */ diff --git a/filter/rastertohp.c b/filter/rastertohp.c new file mode 100644 index 0000000000..85de33ed0d --- /dev/null +++ b/filter/rastertohp.c @@ -0,0 +1,493 @@ +/* + * "$Id$" + * + * Hewlett-Packard Page Control Language and Raster Transfer Language + * filter for ESP Print. + * + * Copyright 1993-1999 by Easy Software Products + * + * These coded instructions, statements, and computer programs contain + * unpublished proprietary information of Easy Software Products, and + * are protected by Federal copyright law. They may not be disclosed + * to third parties or copied or duplicated in any form, in whole or + * in part, without the prior written consent of Easy Software Products. + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Globals... + */ + +unsigned char *Planes[4], /* Output buffers */ + *CompBuffer; /* Compression buffer */ +int NumPlanes, /* Number of color planes */ + Feed; /* Number of lines to skip */ + + +/* + * Prototypes... + */ + +void Setup(void); +void StartPage(cups_page_header_t *header); +void EndPage(cups_page_header_t *header); +void Shutdown(void); + +void CompressData(unsigned char *line, int length, int plane, int type); +void OutputLine(cups_page_header_t *header); + + +/* + * 'Setup()' - Prepare the printer for printing. + */ + +void +Setup(void) +{ + /* + * Send a PCL reset sequence. + */ + + putchar(0x1b); + putchar('E'); +} + + +/* + * 'StartPage()' - Start a page of graphics. + */ + +void +StartPage(cups_page_header_t *header) /* I - Page header */ +{ + int plane; /* Looping var */ + + + /* + * Set the media type, position, and size... + */ + + printf("\033&l6D\033&k12H"); /* Set 6 LPI, 10 CPI */ + printf("\033&l%.2fP", /* Set page length */ + header->PageSize[1] / 12.0); + printf("\033&l%dX", header->NumCopies); /* Set number copies */ + if (header->MediaPosition) + printf("\033&l%dH", header->MediaPosition); /* Set media position */ + if (header->cupsMediaType) + printf("\033&l%dM", /* Set media type */ + header->cupsMediaType); + + /* + * Set graphics mode... + */ + + if (header->cupsColorSpace == CUPS_CSPACE_KCMY) + { + NumPlanes = 4; + printf("\033*r-4U"); /* Set KCMY graphics */ + } + else + NumPlanes = 1; + + printf("\033*t%dR", header->HWResolution[0]); /* Set resolution */ + printf("\033*r%dS", header->cupsWidth); /* Set width */ + printf("\033*r%dT", header->cupsHeight); /* Set height */ + printf("\033&a0H\033&a0V"); /* Set top-of-page */ + printf("\033*r1A"); /* Start graphics */ + + if (header->cupsCompression) + printf("\033*b%dM", /* Set compression */ + header->cupsCompression); + + Feed = 0; /* No blank lines yet */ + + /* + * Allocate memory for a line of graphics... + */ + + Planes[0] = malloc(header->cupsBytesPerLine); + for (plane = 1; plane < NumPlanes; plane ++) + Planes[plane] = Planes[0] + plane * header->cupsBytesPerLine / NumPlanes; + + if (header->cupsCompression) + CompBuffer = malloc(header->cupsBytesPerLine * 2); +} + + +/* + * 'EndPage()' - Finish a page of graphics. + */ + +void +EndPage(cups_page_header_t *header) /* I - Page header */ +{ + /* + * Eject the current page... + */ + + if (NumPlanes > 1) + { + printf("\033*rC"); /* End color GFX */ + printf("\033&l0H"); /* Eject current page */ + } + else + { + printf("\033*r0B"); /* End GFX */ + printf("\014"); /* Eject currnet page */ + } + + /* + * Free memory... + */ + + free(Planes[0]); + + if (header->cupsCompression) + free(CompBuffer); +} + + +/* + * 'Shutdown()' - Shutdown the printer. + */ + +void +Shutdown(void) +{ + /* + * Send a PCL reset sequence. + */ + + putchar(0x1b); + putchar('E'); +} + + +/* + * 'CompressData()' - Compress a line of graphics. + */ + +void +CompressData(unsigned char *line, /* I - Data to compress */ + int length, /* I - Number of bytes */ + int plane, /* I - Color plane */ + int type) /* I - Type of compression */ +{ + unsigned char *line_ptr, /* Current byte pointer */ + *line_end, /* End-of-line byte pointer */ + *comp_ptr, /* Pointer into compression buffer */ + *start; /* Start of compression sequence */ + int count; /* Count of bytes for output */ + + + switch (type) + { + case 0 : + /* + * Do no compression... + */ + + line_ptr = line; + line_end = line + length; + break; + + case 1 : + /* + * Do run-length encoding... + */ + + line_end = line + length; + for (line_ptr = line, comp_ptr = CompBuffer; + line_ptr < line_end; + comp_ptr += 2, line_ptr += count) + { + for (count = 1; + (line_ptr + count) < line_end && + line_ptr[0] == line_ptr[count] && + count < 256; + count ++); + + comp_ptr[0] = count - 1; + comp_ptr[1] = line_ptr[0]; + } + + line_ptr = CompBuffer; + line_end = comp_ptr; + break; + + case 2 : + /* + * Do TIFF pack-bits encoding... + */ + + line_ptr = line; + line_end = line + length; + comp_ptr = CompBuffer; + + while (line_ptr < line_end) + { + if ((line_ptr + 1) >= line_end) + { + /* + * Single byte on the end... + */ + + *comp_ptr++ = 0x00; + *comp_ptr++ = *line_ptr++; + } + else if (line_ptr[0] == line_ptr[1]) + { + /* + * Repeated sequence... + */ + + line_ptr ++; + count = 2; + + while (line_ptr < (line_end - 1) && + line_ptr[0] == line_ptr[1] && + count < 127) + { + line_ptr ++; + count ++; + } + + *comp_ptr++ = 257 - count; + *comp_ptr++ = *line_ptr++; + } + else + { + /* + * Non-repeated sequence... + */ + + start = line_ptr; + line_ptr ++; + count = 1; + + while (line_ptr < (line_end - 1) && + line_ptr[0] != line_ptr[1] && + count < 127) + { + line_ptr ++; + count ++; + } + + *comp_ptr++ = count - 1; + + memcpy(comp_ptr, start, count); + comp_ptr += count; + } + } + + line_ptr = CompBuffer; + line_end = comp_ptr; + break; + } + + /* + * Set the length of the data and write a raster plane... + */ + + printf("\033*b%d%c", line_end - line_ptr, plane); + fwrite(line_ptr, line_end - line_ptr, 1, stdout); +} + + +/* + * 'OutputLine()' - Output a line of graphics. + */ + +void +OutputLine(cups_page_header_t *header) /* I - Page header */ +{ + int plane; /* Current plane */ + + + /* + * Output whitespace as needed... + */ + + if (Feed > 0) + { + printf("\033*b%dY", Feed); + Feed = 0; + } + + /* + * Write bitmap data as needed... + */ + + for (plane = 0; plane < NumPlanes; plane ++) + CompressData(Planes[plane], header->cupsBytesPerLine / NumPlanes, + plane < (NumPlanes - 1) ? 'V' : 'W', + header->cupsCompression); +} + + +/* + * 'main()' - Main entry and processing of driver. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int fd; /* File descriptor */ + cups_raster_t *ras; /* Raster stream for printing */ + cups_page_header_t header; /* Page header from file */ + int page; /* Current page */ + int y; /* Current line */ + + + /* + * Check for valid arguments... + */ + + if (argc < 6 || argc > 7) + { + /* + * We don't have the correct number of arguments; write an error message + * and then sleep for 1 second to give the scheduler a chance to read + * the message. + */ + + fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr); + sleep(1); + return (1); + } + + /* + * Open the page stream... + */ + + if (argc == 7) + { + if ((fd = open(argv[6], O_RDONLY)) == -1) + { + perror("ERROR: Unable to open raster file - "); + sleep(1); + return (1); + } + } + else + fd = 0; + + ras = cupsRasterOpen(fd, CUPS_RASTER_READ); + + /* + * Initialize the print device... + */ + + Setup(); + + /* + * Process pages as needed... + */ + + page = 0; + + while (cupsRasterReadHeader(ras, &header)) + { + /* + * Write a status message with the page number and number of copies. + */ + + page ++; + + fprintf(stderr, "PAGE: %d %d\n", page, header.NumCopies); + + /* + * Start the page... + */ + + StartPage(&header); + + /* + * Loop for each line on the page... + */ + + for (y = 0; y < header.cupsHeight; y ++) + { + /* + * Let the user know how far we have progressed... + */ + + if ((y & 127) == 0) + fprintf(stderr, "INFO: Printing page %d, %d%% complete...\n", page, + 100 * y / header.cupsHeight); + + /* + * Read a line of graphics... + */ + + if (cupsRasterReadPixels(ras, Planes[0], header.cupsBytesPerLine) < 1) + break; + + /* + * See if the line is blank; if not, write it to the printer... + */ + + if (Planes[0][0] || + memcmp(Planes[0], Planes[0] + 1, header.cupsBytesPerLine - 1)) + OutputLine(&header); + else + Feed ++; + } + + /* + * Eject the page... + */ + + EndPage(&header); + } + + /* + * Shutdown the printer... + */ + + Shutdown(); + + /* + * Close the raster stream... + */ + + cupsRasterClose(ras); + if (fd != 0) + close(fd); + + /* + * If no pages were printed, send an error message... + */ + + if (page == 0) + fputs("ERROR: No pages found!\n", stderr); + else + fputs("INFO: Ready to print.\n", stderr); + + /* + * Sleep for 1 second and return... + */ + + sleep(1); + return (page == 0); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/textcommon.c b/filter/textcommon.c new file mode 100644 index 0000000000..2558905a44 --- /dev/null +++ b/filter/textcommon.c @@ -0,0 +1,745 @@ +/* + * "$Id$" + * + * Common text filter routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * TextMain() - Standard main entry for text filters. + * compare_keywords() - Compare two C/C++ keywords. + * getutf8() - Get a UTF-8 encoded wide character... + */ + +/* + * Include necessary headers... + */ + +#include "textcommon.h" + + +/* + * Globals... + */ + +int WrapLines = 1, /* Wrap text in lines */ + SizeLines = 60, /* Number of lines on a page */ + SizeColumns = 80, /* Number of columns on a line */ + PageColumns = 1, /* Number of columns on a page */ + ColumnGutter = 0, /* Number of characters between text columns */ + ColumnWidth = 80, /* Width of each column */ + PrettyPrint = 0, /* Do pretty code formatting */ + Copies = 1; /* Number of copies */ +lchar_t **Page = NULL; /* Page characters */ +int NumPages = 0; /* Number of pages in document */ +int CharsPerInch = 10; /* Number of character columns per inch */ +int LinesPerInch = 6; /* Number of lines per inch */ +int UTF8 = 0; /* Use UTF-8 encoding? */ +char *Keywords[] = /* List of known keywords... */ + { + "and", + "and_eq", + "asm", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "class", + "compl", + "const", + "continue", + "default", + "delete", + "do", + "double", + "else", + "enum", + "explicit", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "inline", + "int", + "long", + "mutable", + "namespace", + "new", + "not", + "not_eq", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "return", + "short", + "signed", + "sizeof", + "static", + "struct", + "switch", + "template", + "this", + "throw", + "true", + "try", + "typedef", + "typename", + "union", + "unsigned", + "virtual", + "void", + "volatile", + "while", + "xor", + "xor_eq" + }; + + +/* + * Local functions... + */ + +static int compare_keywords(const void *, const void *); +static int getutf8(FILE *fp); + + +/* + * 'TextMain()' - Standard main entry for text filters. + */ + +int /* O - Exit status */ +TextMain(char *name, /* I - Name of filter */ + int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + FILE *fp; /* Print file */ + ppd_file_t *ppd; /* PPD file */ + int i, /* Looping var */ + ch, /* Current char from file */ + lastch, /* Previous char from file */ + attr, /* Current attribute */ + line, /* Current line */ + column, /* Current column */ + page_column; /* Current page column */ + int num_options; /* Number of print options */ + cups_option_t *options; /* Print options */ + const char *val; /* Option value */ + char keyword[64], /* Keyword string */ + *keyptr; /* Pointer into string */ + int keycol; /* Column where keyword starts */ + int ccomment; /* Inside a C-style comment? */ + int cstring; /* Inside a C string */ + + + if (argc < 6 || argc > 7) + { + fprintf(stderr, "ERROR: %s job-id user title copies options [file]\n", + name); + return (1); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + fp = stdin; + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file - "); + return (1); + } + } + + /* + * Process command-line options and write the prolog... + */ + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + if ((val = cupsGetOption("prettyprint", num_options, options)) != NULL) + { + PrettyPrint = 1; + PageLeft = 72.0f; + PageRight = PageWidth - 36.0f; + PageBottom = PageBottom > 36.0f ? PageBottom : 36.0f; + PageTop = PageLength - 36.0f; + CharsPerInch = 12; + LinesPerInch = 8; + } + + if ((ppd = SetCommonOptions(num_options, options, 1)) != NULL) + ppdClose(ppd); + + WrapLines = cupsGetOption("nowrap", num_options, options) == NULL; + + if ((val = cupsGetOption("columns", num_options, options)) != NULL) + PageColumns = atoi(val); + + if ((val = cupsGetOption("cpi", num_options, options)) != NULL) + CharsPerInch = atoi(val); + + if ((val = cupsGetOption("lpi", num_options, options)) != NULL) + LinesPerInch = atoi(val); + + if ((val = cupsGetOption("prettyprint", num_options, options)) != NULL) + PageTop -= 216.0f / LinesPerInch; + + Copies = atoi(argv[4]); + + WriteProlog(argv[3], argv[2], ppd); + + /* + * Read text from the specified source and print it... + */ + + column = 0; + line = 0; + page_column = 0; + attr = 0; + keyptr = keyword; + keycol = 0; + ccomment = 0; + cstring = 0; + + while ((ch = getutf8(fp)) >= 0) + { + /* + * Control codes: + * + * BS Backspace (0x08) + * HT Horizontal tab; next 8th column (0x09) + * LF Line feed; forward full line (0x0a) + * VT Vertical tab; reverse full line (0x0b) + * FF Form feed (0x0c) + * CR Carriage return (0x0d) + * ESC 7 Reverse full line (0x1b 0x37) + * ESC 8 Reverse half line (0x1b 0x38) + * ESC 9 Forward half line (0x1b 0x39) + */ + + switch (ch) + { + case 0x08 : /* BS - backspace for boldface & underline */ + if (column > 0) + column --; + + keyptr = keyword; + keycol = column; + break; + + case 0x09 : /* HT - tab to next 8th column */ + if (PrettyPrint && keyptr > keyword) + { + *keyptr = '\0'; + keyptr = keyword; + + if (bsearch(&keyptr, Keywords, sizeof(Keywords) / sizeof(Keywords[0]), + sizeof(Keywords[0]), compare_keywords)) + { + /* + * Put keywords in boldface... + */ + + i = page_column * (ColumnWidth + ColumnGutter); + + while (keycol < column) + { + Page[line][keycol + i].attr |= ATTR_BOLD; + keycol ++; + } + } + } + + column = (column + 8) & ~7; + + if (column >= ColumnWidth && WrapLines) + { /* Wrap text to margins */ + line ++; + column = 0; + + if (line >= SizeLines) + { + page_column ++; + line = 0; + + if (page_column >= PageColumns) + { + WritePage(); + page_column = 0; + } + } + } + + keycol = column; + break; + + case 0x0a : /* LF - output current line */ + if (PrettyPrint && keyptr > keyword) + { + *keyptr = '\0'; + keyptr = keyword; + + if (bsearch(&keyptr, Keywords, sizeof(Keywords) / sizeof(Keywords[0]), + sizeof(Keywords[0]), compare_keywords)) + { + /* + * Put keywords in boldface... + */ + + i = page_column * (ColumnWidth + ColumnGutter); + + while (keycol < column) + { + Page[line][keycol + i].attr |= ATTR_BOLD; + keycol ++; + } + } + } + + line ++; + column = 0; + keycol = 0; + + if (!ccomment && !cstring) + attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE); + + if (line >= SizeLines) + { + page_column ++; + line = 0; + + if (page_column >= PageColumns) + { + WritePage(); + page_column = 0; + } + } + break; + + case 0x0b : /* VT - move up 1 line */ + if (line > 0) + line --; + + keyptr = keyword; + keycol = column; + + if (!ccomment && !cstring) + attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE); + break; + + case 0x0c : /* FF - eject current page... */ + if (PrettyPrint && keyptr > keyword) + { + *keyptr = '\0'; + keyptr = keyword; + + if (bsearch(&keyptr, Keywords, sizeof(Keywords) / sizeof(Keywords[0]), + sizeof(Keywords[0]), compare_keywords)) + { + /* + * Put keywords in boldface... + */ + + i = page_column * (ColumnWidth + ColumnGutter); + + while (keycol < column) + { + Page[line][keycol + i].attr |= ATTR_BOLD; + keycol ++; + } + } + } + + page_column ++; + column = 0; + keycol = 0; + line = 0; + + if (!ccomment && !cstring) + attr &= ~(ATTR_ITALIC | ATTR_BOLD | ATTR_RED | ATTR_GREEN | ATTR_BLUE); + + if (page_column >= PageColumns) + { + WritePage(); + page_column = 0; + } + break; + + case 0x0d : /* CR */ + column = 0; + break; + + case 0x1b : /* Escape sequence */ + ch = getutf8(fp); + if (ch == '7') + { + /* + * ESC 7 Reverse full line (0x1b 0x37) + */ + + if (line > 0) + line --; + } + else if (ch == '8') + { + /* + * ESC 8 Reverse half line (0x1b 0x38) + */ + + if ((attr & ATTR_RAISED) && line > 0) + { + attr &= ~ATTR_RAISED; + line --; + } + else if (attr & ATTR_LOWERED) + attr &= ~ATTR_LOWERED; + else + attr |= ATTR_RAISED; + } + else if (ch == '9') + { + /* + * ESC 9 Forward half line (0x1b 0x39) + */ + + if ((attr & ATTR_LOWERED) && line < (SizeLines - 1)) + { + attr &= ~ATTR_LOWERED; + line ++; + } + else if (attr & ATTR_RAISED) + attr &= ~ATTR_RAISED; + else + attr |= ATTR_LOWERED; + } + break; + + default : /* All others... */ + if (ch < ' ') + break; /* Ignore other control chars */ + + if (PrettyPrint) + { + /* + * Do highlighting of C/C++ keywords, preprocessor commands, + * and comments... + */ + + if ((ch == ' ' || ch == '\t') && (attr & ATTR_BOLD)) + { + /* + * Stop bolding preprocessor command... + */ + + attr &= ~ATTR_BOLD; + } + else if (!(isalnum(ch) || ch == '_') && keyptr > keyword) + { + /* + * Look for a keyword... + */ + + *keyptr = '\0'; + keyptr = keyword; + + if (!(attr & ATTR_ITALIC) && + bsearch(&keyptr, Keywords, sizeof(Keywords) / sizeof(Keywords[0]), + sizeof(Keywords[0]), compare_keywords)) + { + /* + * Put keywords in boldface... + */ + + i = page_column * (ColumnWidth + ColumnGutter); + + while (keycol < column) + { + Page[line][keycol + i].attr |= ATTR_BOLD; + keycol ++; + } + } + } + else if ((isalnum(ch) || ch == '_') && !ccomment && !cstring) + { + /* + * Add characters to the current keyword (if they'll fit). + */ + + if (keyptr == keyword) + keycol = column; + + if (keyptr < (keyword + sizeof(keyword) - 1)) + *keyptr++ = ch; + } + else if (ch == '\"' && lastch != '\\' && !ccomment && !cstring) + { + /* + * Start a C string constant... + */ + + cstring = -1; + attr |= ATTR_BLUE; + } + else if (ch == '*' && lastch == '/' && !cstring) + { + /* + * Start a C-style comment... + */ + + ccomment = 1; + attr |= ATTR_ITALIC | ATTR_GREEN; + } + else if (ch == '/' && lastch == '/' && !cstring) + { + /* + * Start a C++-style comment... + */ + + attr |= ATTR_ITALIC | ATTR_GREEN; + } + else if (ch == '#' && column == 0 && !ccomment && !cstring) + { + /* + * Start a preprocessor command... + */ + + attr |= ATTR_BOLD | ATTR_RED; + } + } + + if (column >= ColumnWidth && WrapLines) + { /* Wrap text to margins */ + column = 0; + line ++; + + if (line >= SizeLines) + { + page_column ++; + line = 0; + + if (page_column >= PageColumns) + { + WritePage(); + page_column = 0; + } + } + } + + /* + * Add text to the current column & line... + */ + + if (column < ColumnWidth) + { + i = column + page_column * (ColumnWidth + ColumnGutter); + + if (PrettyPrint) + Page[line][i].attr = attr; + 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 + Page[line][i].attr = attr; + + Page[line][i].ch = ch; + } + + if (PrettyPrint) + { + if ((ch == '{' || ch == '}') && !ccomment && !cstring && + column < ColumnWidth) + { + /* + * Highlight curley braces... + */ + + Page[line][i].attr |= ATTR_BOLD; + } + else if ((ch == '/' || ch == '*') && lastch == '/' && + column < ColumnWidth) + { + /* + * Highlight first comment character... + */ + + Page[line][i - 1].attr = attr; + } + else if (ch == '\"' && lastch != '\\' && !ccomment && cstring > 0) + { + /* + * End a C string constant... + */ + + cstring = 0; + attr &= ~ATTR_BLUE; + } + else if (ch == '/' && lastch == '*' && ccomment) + { + /* + * End a C-style comment... + */ + + ccomment = 0; + attr &= ~(ATTR_ITALIC | ATTR_GREEN); + } + + if (cstring < 0) + cstring = 1; + } + + column ++; + break; + } + + /* + * Save this character for the next cycle. + */ + + lastch = ch; + } + + /* + * Write any remaining page data... + */ + + if (line > 0 || page_column > 0 || column > 0) + WritePage(); + + /* + * Write the epilog and return... + */ + + WriteEpilogue(); + + return (0); +} + + +/* + * 'compare_keywords()' - Compare two C/C++ keywords. + */ + +static int /* O - Result of strcmp */ +compare_keywords(const void *k1, /* I - First keyword */ + const void *k2) /* I - Second keyword */ +{ + return (strcmp(*((const char **)k1), *((const char **)k2))); +} + + +/* + * 'getutf8()' - Get a UTF-8 encoded wide character... + */ + +static int /* O - Character or -1 on error */ +getutf8(FILE *fp) /* I - File to read from */ +{ + int ch; /* Current character value */ + int next; /* Next character from file */ + + + /* + * Read the first character and process things accordingly... + * + * UTF-8 maps 16-bit characters to: + * + * 0 to 127 = 0xxxxxxx + * 128 to 2047 = 110xxxxx 10yyyyyy (xxxxxyyyyyy) + * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz (xxxxyyyyyyzzzzzz) + * + * We also accept: + * + * 128 to 191 = 10xxxxxx + * + * since this range of values is otherwise undefined unless you are + * in the middle of a multi-byte character... + * + * This code currently does not support anything beyond 16-bit + * characters, in part because PostScript doesn't support more than + * 16-bit characters... + */ + + if ((ch = getc(fp)) == EOF) + return (EOF); + + if (ch < 0xc0 || !UTF8) /* One byte character? */ + return (ch); + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two byte character... + */ + + if ((next = getc(fp)) == EOF) + return (EOF); + else + return (((ch & 0x1f) << 6) | (next & 0x3f)); + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three byte character... + */ + + if ((next = getc(fp)) == EOF) + return (EOF); + + ch = ((ch & 0x0f) << 6) | (next & 0x3f); + + if ((next = getc(fp)) == EOF) + return (EOF); + else + return ((ch << 6) | (next & 0x3f)); + } + else + { + /* + * More than three bytes... We don't support that... + */ + + return (EOF); + } +} + + +/* + * End of "$Id$". + */ diff --git a/filter/textcommon.h b/filter/textcommon.h new file mode 100644 index 0000000000..cffd4db731 --- /dev/null +++ b/filter/textcommon.h @@ -0,0 +1,89 @@ +/* + * "$Id$" + * + * Common text filter definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Include necessary headers... + */ + +#include "common.h" + + +/* + * Constants... + */ + +#define ATTR_BOLD 0x01 +#define ATTR_UNDERLINE 0x02 +#define ATTR_RAISED 0x04 +#define ATTR_LOWERED 0x08 +#define ATTR_ITALIC 0x10 +#define ATTR_RED 0x20 +#define ATTR_GREEN 0x40 +#define ATTR_BLUE 0x80 + + +/* + * Structures... + */ + +typedef struct /**** Character/attribute structure... ****/ +{ + unsigned short ch, /* Character */ + attr; /* Any attributes */ +} lchar_t; + + +/* + * Globals... + */ + +extern int WrapLines, /* Wrap text in lines */ + SizeLines, /* Number of lines on a page */ + SizeColumns, /* Number of columns on a line */ + PageColumns, /* Number of columns on a page */ + ColumnGutter, /* Number of characters between text columns */ + ColumnWidth, /* Width of each column */ + PrettyPrint, /* Do pretty code formatting */ + Copies; /* Number of copies to produce */ +extern lchar_t **Page; /* Page characters */ +extern int NumPages; /* Number of pages in document */ +extern int CharsPerInch, /* Number of character columns per inch */ + LinesPerInch, /* Number of lines per inch */ + UTF8; /* Use UTF-8 encoding? */ +extern char *Keywords[]; /* List of known keywords... */ + + +/* + * Required functions... + */ + +extern int TextMain(char *name, int argc, char *argv[]); +extern void WriteEpilogue(void); +extern void WritePage(void); +extern void WriteProlog(char *title, char *user, ppd_file_t *ppd); + + +/* + * End of "$Id$". + */ diff --git a/filter/texttops.c b/filter/texttops.c new file mode 100644 index 0000000000..b8757bf9c3 --- /dev/null +++ b/filter/texttops.c @@ -0,0 +1,568 @@ +/* + * "$Id$" + * + * Text to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for text to PostScript filter. + * WriteEpilogue() - Write the PostScript file epilogue. + * WritePage() - Write a page of text. + * WriteProlog() - Write the PostScript file prolog with options. + * write_line() - Write a row of text. + * write_string() - Write a string of text. + */ + +/* + * Include necessary headers... + */ + +#include "textcommon.h" + + +/* + * Globals... + */ + +char *Glyphs[65536]; /* PostScript glyphs for Unicode */ + +/* + * Local functions... + */ + +static void write_line(int row, lchar_t *line); +static void write_string(int col, int row, int len, lchar_t *s); + + +/* + * 'main()' - Main entry for text to PostScript filter. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + return (TextMain("texttops", argc, argv)); +} + + +/* + * 'WriteEpilogue()' - Write the PostScript file epilogue. + */ + +void +WriteEpilogue(void) +{ + puts("%%BeginTrailer"); + printf("%%%%Pages: %d\n", NumPages); + puts("%%EOF"); + + free(Page[0]); + free(Page); +} + + +/* + * 'WritePage()' - Write a page of text. + */ + +void +WritePage(void) +{ + int line; /* Current line */ + + + NumPages ++; + printf("%%%%Page: %d %d\n", NumPages, NumPages); + + puts("gsave"); + + if (PrettyPrint) + printf("%d H\n", NumPages); + + for (line = 0; line < SizeLines; line ++) + write_line(line, Page[line]); + + puts("grestore"); + puts("showpage"); + + memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines); +} + + +/* + * 'WriteProlog()' - Write the PostScript file prolog with options. + */ + +void +WriteProlog(char *title, /* I - Title of job */ + char *user, /* I - Username */ + ppd_file_t *ppd) /* I - PPD file info */ +{ + int line; /* Current output line */ + char *charset; /* Character set string */ + char filename[1024]; /* Glyph filenames */ + FILE *fp; /* Glyph files */ + int ch, unicode; /* Character values */ + char glyph[64]; /* Glyph name */ + int chars[256]; /* Character encoding array */ + time_t curtime; /* Current time */ + struct tm *curtm; /* Current date */ + char curdate[255]; /* Current date (text format) */ + + + curtime = time(NULL); + curtm = localtime(&curtime); + strftime(curdate, sizeof(curdate), "%c", curtm); + + puts("%!PS-Adobe-3.0"); + printf("%%%%BoundingBox: %.0f %.0f %.0f %.0f\n", PageLeft, PageBottom, + PageRight, PageTop); + if (Orientation & 1) + puts("%%Orientation: Landscape"); + puts("%%Creator: texttops/" CUPS_SVERSION); + printf("%%%%CreationDate: %s\n", curdate); + printf("%%%%Title: %s\n", title); + printf("%%%%For: %s\n", user); + if (PrettyPrint) + puts("%%DocumentNeededResources: font Courier Courier-Bold Courier-Oblique"); + else + puts("%%DocumentNeededResources: font Courier Courier-Bold"); + puts("%%DocumentSuppliedResources: procset texttops 1.0 0"); + puts("%%Pages: (atend)"); + + puts("%%EndComments"); + + SizeColumns = (PageRight - PageLeft) / 72.0 * CharsPerInch; + SizeLines = (PageTop - PageBottom) / 72.0 * LinesPerInch; + + Page = calloc(sizeof(lchar_t *), SizeLines); + Page[0] = calloc(sizeof(lchar_t), SizeColumns * SizeLines); + for (line = 1; line < SizeLines; line ++) + Page[line] = Page[0] + line * SizeColumns; + + if (PageColumns > 1) + { + ColumnGutter = CharsPerInch / 2; + ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) / + PageColumns; + } + else + ColumnWidth = SizeColumns; + + /* + * Get the output character set; if it is undefined or "us-ascii", do + * nothing because we can use the default encoding... + */ + + puts("%%BeginProlog"); + puts("%%BeginResource: procset texttops 1.0 0"); + + charset = getenv("CHARSET"); + if (charset != NULL && strcmp(charset, "us-ascii") != 0) + { + /* + * Load the PostScript glyph names and the corresponding character + * set definition... + */ + + memset(Glyphs, 0, sizeof(Glyphs)); + + if ((fp = fopen(CUPS_DATADIR "/data/psglyphs", "r")) != NULL) + { + while (fscanf(fp, "%x%s", &unicode, glyph) == 2) + Glyphs[unicode] = strdup(glyph); + + fclose(fp); + } + + if (strncmp(charset, "iso-", 4) == 0) + { + memset(chars, 0, sizeof(chars)); + + sprintf(filename, CUPS_DATADIR "/%s", charset + 4); + + if ((fp = fopen(filename, "r")) != NULL) + { + while (fscanf(fp, "%x%x", &ch, &unicode) == 2) + chars[ch] = unicode; + + fclose(fp); + } + } + else + { + /* + * UTF-8 encoding - just pass the first 256 characters for now... + */ + + UTF8 = 1; + + for (unicode = 0; unicode < 256; unicode ++) + chars[unicode] = unicode; + } + + /* + * Write the encoding array... + */ + + printf("%% %s encoding\n", charset); + puts("/textEncoding ["); + + for (ch = 0; ch < 256; ch ++) + { + if (Glyphs[chars[ch]]) + printf("/%s", Glyphs[chars[ch]]); + else + printf("/.notdef"); + + if ((ch & 7) == 7) + putchar('\n'); + } + + puts("] def"); + + puts("% Reencode fonts"); + puts("/Courier findfont"); + puts("dup length dict begin\n" + " { 1 index /FID ne { def } { pop pop } ifelse } forall\n" + " /Encoding textEncoding def\n" + " currentdict\n" + "end"); + puts("/Courier exch definefont pop"); + + puts("/Courier-Bold findfont"); + puts("dup length dict begin\n" + " { 1 index /FID ne { def } { pop pop } ifelse } forall\n" + " /Encoding textEncoding def\n" + " currentdict\n" + "end"); + puts("/Courier-Bold exch definefont pop"); + + if (PrettyPrint) + { + puts("/Courier-Oblique findfont"); + puts("dup length dict begin\n" + " { 1 index /FID ne { def } { pop pop } ifelse } forall\n" + " /Encoding textEncoding def\n" + " currentdict\n" + "end"); + puts("/Courier-Oblique exch definefont pop"); + } + } + + puts("% Define fonts"); + + printf("/FN /Courier findfont [%.1f 0 0 %.1f 0 0] makefont def\n", + 120.0 / CharsPerInch, 68.0 / LinesPerInch); + printf("/FB /Courier-Bold findfont [%.1f 0 0 %.1f 0 0] makefont def\n", + 120.0 / CharsPerInch, 68.0 / LinesPerInch); + if (PrettyPrint) + printf("/FI /Courier-Oblique findfont [%.1f 0 0 %.1f 0 0] makefont def\n", + 120.0 / CharsPerInch, 68.0 / LinesPerInch); + + puts("% Common procedures"); + + puts("/N { FN setfont moveto } bind def"); + puts("/B { FB setfont moveto } bind def"); + puts("/U { gsave 0 rlineto stroke grestore } bind def"); + + if (PrettyPrint) + { + if (ColorDevice) + { + puts("/S { 0.0 setgray show } bind def"); + puts("/r { 0.5 0.0 0.0 setrgbcolor show } bind def"); + puts("/g { 0.0 0.5 0.0 setrgbcolor show } bind def"); + puts("/b { 0.0 0.0 0.5 setrgbcolor show } bind def"); + } + else + { + puts("/S { 0.0 setgray show } bind def"); + puts("/r { 0.2 setgray show } bind def"); + puts("/g { 0.2 setgray show } bind def"); + puts("/b { 0.2 setgray show } bind def"); + } + + puts("/I { FI setfont moveto } bind def"); + + puts("/P 20 string def"); + printf("/T("); + + while (*title != '\0') + { + if (*title == '(' || *title == ')' || *title == '\\') + putchar('\\'); + + putchar(*title++); + } + + puts(")def"); + + puts("/H {"); + puts("gsave"); + puts("\t0.9 setgray"); + + if (Duplex) + { + puts("\tdup 2 mod 0 eq {"); + printf("\t\t%.1f %.1f translate } {\n", + PageWidth - PageRight, PageTop + 72.0f / LinesPerInch); + printf("\t\t%.1f %.1f translate } ifelse\n", + PageLeft, PageTop + 72.0f / LinesPerInch); + } + else + printf("\t%.1f %.1f translate\n", + PageLeft, PageTop + 72.0f / LinesPerInch); + + printf("\t0 0 %.1f %.1f rectfill\n", PageRight - PageLeft, + 144.0f / LinesPerInch); + + puts("\tFB setfont"); + puts("\t0 setgray"); + + if (Duplex) + { + puts("\tdup 2 mod 0 eq {"); + printf("\t\tT stringwidth pop neg %.1f add %.1f } {\n", + PageRight - PageLeft - 36.0f / LinesPerInch, + (0.5f + 0.157f) * 72.0f / LinesPerInch); + printf("\t\t%.1f %.1f } ifelse\n", 36.0f / LinesPerInch, + (0.5f + 0.157f) * 72.0f / LinesPerInch); + } + else + printf("\t%.1f %.1f\n", 36.0f / LinesPerInch, + (0.5f + 0.157f) * 72.0f / LinesPerInch); + + puts("\tmoveto T show"); + + printf("\t(%s)\n", curdate); + printf("\tdup stringwidth pop neg 2 div %.1f add %.1f\n", + (PageRight - PageLeft) * 0.5, + (0.5f + 0.157f) * 72.0f / LinesPerInch); + puts("\tmoveto show"); + + if (Duplex) + { + puts("\tdup P cvs exch 2 mod 0 eq {"); + printf("\t\t%.1f %.1f } {\n", 36.0f / LinesPerInch, + (0.5f + 0.157f) * 72.0f / LinesPerInch); + printf("\t\tdup stringwidth pop neg %.1f add %.1f } ifelse\n", + PageRight - PageLeft - 36.0f / LinesPerInch, + (0.5f + 0.157f) * 72.0f / LinesPerInch); + } + else + printf("\tP cvs dup stringwidth pop neg %.1f add %.1f\n", + PageRight - PageLeft - 36.0f / LinesPerInch, + (0.5f + 0.157f) * 72.0f / LinesPerInch); + + puts("\tmoveto show"); + puts("\tgrestore"); + puts("} bind def"); + } + else + puts("/S { show } bind def"); + + puts("%%EndResource"); + + puts("%%EndProlog"); +} + + +/* + * 'write_line()' - Write a row of text. + */ + +static void +write_line(int row, /* I - Row number (0 to N) */ + lchar_t *line) /* I - Line to print */ +{ + int col; /* Current column */ + int attr; /* Current attribute */ + lchar_t *start; /* First character in sequence */ + + + for (col = 0, start = line; col < SizeColumns;) + { + while (col < SizeColumns && (line->ch == ' ' || line->ch == 0)) + { + col ++; + line ++; + } + + if (col >= SizeColumns) + break; + + attr = line->attr; + start = line; + + while (col < SizeColumns && line->ch != 0 && attr == line->attr) + { + col ++; + line ++; + } + + write_string(col - (line - start), row, line - start, start); + } +} + + +/* + * 'write_string()' - Write a string of text. + */ + +static void +write_string(int col, /* I - Start column */ + int row, /* I - Row */ + int len, /* I - Number of characters */ + lchar_t *s) /* I - String to print */ +{ + int i; /* Looping var */ + float x, y; /* Position of text */ + unsigned attr; /* Character attributes */ + + + /* + * Position the text and set the font... + */ + + if (Duplex && (NumPages & 1) == 0) + { + x = PageWidth - PageRight; + y = PageTop; + } + else + { + x = PageLeft; + y = PageTop; + } + + x += (float)col * 72.0f / (float)CharsPerInch; + y -= (float)(row + 0.843) * 72.0f / (float)LinesPerInch; + + attr = s->attr; + + if (attr & ATTR_RAISED) + y += 36.0 / (float)LinesPerInch; + else if (attr & ATTR_LOWERED) + y -= 36.0 / (float)LinesPerInch; + + if (x == (int)x) + printf("%.0f ", x); + else + printf("%.1f ", x); + + if (y == (int)y) + printf("%.0f ", y); + else + printf("%.1f ", y); + + if (attr & ATTR_BOLD) + putchar('B'); + else if (attr & ATTR_ITALIC) + putchar('I'); + else + putchar('N'); + + if (attr & ATTR_UNDERLINE) + printf(" %.1f U", (float)len * 72.0 / (float)CharsPerInch); + + /* + * See if the string contains 16-bit characters... + */ + + for (i = 0; i < len; i ++) + if (s[i].ch > 255) + break; + + if (i < len) + { + /* + * Write a hex Unicode string... + */ + + fputs(" 0) + { + printf("%04x", s->ch); + len --; + s ++; + } + + putchar('>'); + } + else + { + /* + * Write a quoted string... + */ + + putchar('('); + + while (len > 0) + { + if (s->ch > 126) + { + /* + * Quote 8-bit characters... + */ + + printf("\\%03o", s->ch); + } + else + { + /* + * Quote the parenthesis and backslash as needed... + */ + + if (s->ch == '(' || s->ch == ')' || s->ch == '\\') + putchar('\\'); + + putchar(s->ch); + } + + len --; + s ++; + } + + putchar(')'); + } + + if (PrettyPrint) + { + if (attr & ATTR_RED) + puts("r"); + else if (attr & ATTR_GREEN) + puts("g"); + else if (attr & ATTR_BLUE) + puts("b"); + else + puts("S"); + } + else + puts("S"); +} + + +/* + * End of "$Id$". + */ diff --git a/fonts/AvantGarde-Book b/fonts/AvantGarde-Book new file mode 100644 index 0000000000..ff3b81847e Binary files /dev/null and b/fonts/AvantGarde-Book differ diff --git a/fonts/AvantGarde-BookOblique b/fonts/AvantGarde-BookOblique new file mode 100644 index 0000000000..12af8ae8d7 Binary files /dev/null and b/fonts/AvantGarde-BookOblique differ diff --git a/fonts/AvantGarde-Demi b/fonts/AvantGarde-Demi new file mode 100644 index 0000000000..e0df0c7095 Binary files /dev/null and b/fonts/AvantGarde-Demi differ diff --git a/fonts/AvantGarde-DemiOblique b/fonts/AvantGarde-DemiOblique new file mode 100644 index 0000000000..de6c3491ef Binary files /dev/null and b/fonts/AvantGarde-DemiOblique differ diff --git a/fonts/Bookman-Demi b/fonts/Bookman-Demi new file mode 100644 index 0000000000..da92e614cd Binary files /dev/null and b/fonts/Bookman-Demi differ diff --git a/fonts/Bookman-DemiItalic b/fonts/Bookman-DemiItalic new file mode 100644 index 0000000000..59072a526f Binary files /dev/null and b/fonts/Bookman-DemiItalic differ diff --git a/fonts/Bookman-Light b/fonts/Bookman-Light new file mode 100644 index 0000000000..4416dbf312 Binary files /dev/null and b/fonts/Bookman-Light differ diff --git a/fonts/Bookman-LightItalic b/fonts/Bookman-LightItalic new file mode 100644 index 0000000000..b8522c63cf Binary files /dev/null and b/fonts/Bookman-LightItalic differ diff --git a/fonts/Courier b/fonts/Courier new file mode 100644 index 0000000000..54fe52724b Binary files /dev/null and b/fonts/Courier differ diff --git a/fonts/Courier-Bold b/fonts/Courier-Bold new file mode 100644 index 0000000000..7b31de35f3 Binary files /dev/null and b/fonts/Courier-Bold differ diff --git a/fonts/Courier-BoldOblique b/fonts/Courier-BoldOblique new file mode 100644 index 0000000000..45b11a12f7 Binary files /dev/null and b/fonts/Courier-BoldOblique differ diff --git a/fonts/Courier-Oblique b/fonts/Courier-Oblique new file mode 100644 index 0000000000..bbd2f05345 Binary files /dev/null and b/fonts/Courier-Oblique differ diff --git a/fonts/Helvetica b/fonts/Helvetica new file mode 100644 index 0000000000..5f20a5aade Binary files /dev/null and b/fonts/Helvetica differ diff --git a/fonts/Helvetica-Bold b/fonts/Helvetica-Bold new file mode 100644 index 0000000000..85ef201db5 Binary files /dev/null and b/fonts/Helvetica-Bold differ diff --git a/fonts/Helvetica-BoldOblique b/fonts/Helvetica-BoldOblique new file mode 100644 index 0000000000..48c34c1ca2 Binary files /dev/null and b/fonts/Helvetica-BoldOblique differ diff --git a/fonts/Helvetica-Narrow b/fonts/Helvetica-Narrow new file mode 100644 index 0000000000..e81691b52c Binary files /dev/null and b/fonts/Helvetica-Narrow differ diff --git a/fonts/Helvetica-Narrow-Bold b/fonts/Helvetica-Narrow-Bold new file mode 100644 index 0000000000..9ff5394163 Binary files /dev/null and b/fonts/Helvetica-Narrow-Bold differ diff --git a/fonts/Helvetica-Narrow-BoldOblique b/fonts/Helvetica-Narrow-BoldOblique new file mode 100644 index 0000000000..9ca742cd63 Binary files /dev/null and b/fonts/Helvetica-Narrow-BoldOblique differ diff --git a/fonts/Helvetica-Narrow-Oblique b/fonts/Helvetica-Narrow-Oblique new file mode 100644 index 0000000000..04045ae3f4 Binary files /dev/null and b/fonts/Helvetica-Narrow-Oblique differ diff --git a/fonts/Helvetica-Oblique b/fonts/Helvetica-Oblique new file mode 100644 index 0000000000..0653f80bf5 Binary files /dev/null and b/fonts/Helvetica-Oblique differ diff --git a/fonts/Makefile b/fonts/Makefile new file mode 100644 index 0000000000..f287800b1d --- /dev/null +++ b/fonts/Makefile @@ -0,0 +1,68 @@ +# +# "$Id$" +# +# Fonts makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Font files... +# + +FONTS = AvantGarde-Book AvantGarde-BookOblique AvantGarde-Demi \ + AvantGarde-DemiOblique Bookman-Demi Bookman-DemiItalic \ + Bookman-Light Bookman-LightItalic Courier Courier-Bold \ + Courier-BoldOblique Courier-Oblique Helvetica \ + Helvetica-Bold Helvetica-BoldOblique Helvetica-Narrow \ + Helvetica-Narrow-Bold Helvetica-Narrow-BoldOblique \ + Helvetica-Narrow-Oblique Helvetica-Oblique \ + NewCenturySchlbk-Bold NewCenturySchlbk-BoldItalic \ + NewCenturySchlbk-Italic NewCenturySchlbk-Roman \ + Palatino-Bold Palatino-BoldItalic Palatino-Italic \ + Palatino-Roman Symbol Times-Bold Times-BoldItalic \ + Times-Italic Times-Roman Utopia-Bold Utopia-BoldItalic \ + Utopia-Italic Utopia-Regular ZapfChancery-MediumItalic \ + ZapfDingbats + +# +# Make everything... +# + +all: + +# +# Clean all config and object files... +# + +clean: + +# +# Install files... +# + +install: + -$(MKDIR) $(DATADIR)/fonts + $(CP) $(FONTS) $(DATADIR)/fonts + +# +# End of "$Id$". +# diff --git a/fonts/NewCenturySchlbk-Bold b/fonts/NewCenturySchlbk-Bold new file mode 100644 index 0000000000..41876dcd2e Binary files /dev/null and b/fonts/NewCenturySchlbk-Bold differ diff --git a/fonts/NewCenturySchlbk-BoldItalic b/fonts/NewCenturySchlbk-BoldItalic new file mode 100644 index 0000000000..8ed9fdf522 Binary files /dev/null and b/fonts/NewCenturySchlbk-BoldItalic differ diff --git a/fonts/NewCenturySchlbk-Italic b/fonts/NewCenturySchlbk-Italic new file mode 100644 index 0000000000..d213425856 Binary files /dev/null and b/fonts/NewCenturySchlbk-Italic differ diff --git a/fonts/NewCenturySchlbk-Roman b/fonts/NewCenturySchlbk-Roman new file mode 100644 index 0000000000..46df4a4d9f Binary files /dev/null and b/fonts/NewCenturySchlbk-Roman differ diff --git a/fonts/Palatino-Bold b/fonts/Palatino-Bold new file mode 100644 index 0000000000..8f8ef3649e Binary files /dev/null and b/fonts/Palatino-Bold differ diff --git a/fonts/Palatino-BoldItalic b/fonts/Palatino-BoldItalic new file mode 100644 index 0000000000..da1128f142 Binary files /dev/null and b/fonts/Palatino-BoldItalic differ diff --git a/fonts/Palatino-Italic b/fonts/Palatino-Italic new file mode 100644 index 0000000000..c8d447a64c Binary files /dev/null and b/fonts/Palatino-Italic differ diff --git a/fonts/Palatino-Roman b/fonts/Palatino-Roman new file mode 100644 index 0000000000..ba252bdcb5 Binary files /dev/null and b/fonts/Palatino-Roman differ diff --git a/fonts/Symbol b/fonts/Symbol new file mode 100644 index 0000000000..e96e6e0452 Binary files /dev/null and b/fonts/Symbol differ diff --git a/fonts/Times-Bold b/fonts/Times-Bold new file mode 100644 index 0000000000..b03ed85d48 Binary files /dev/null and b/fonts/Times-Bold differ diff --git a/fonts/Times-BoldItalic b/fonts/Times-BoldItalic new file mode 100644 index 0000000000..7fcda18073 Binary files /dev/null and b/fonts/Times-BoldItalic differ diff --git a/fonts/Times-Italic b/fonts/Times-Italic new file mode 100644 index 0000000000..b4b018a8d9 Binary files /dev/null and b/fonts/Times-Italic differ diff --git a/fonts/Times-Roman b/fonts/Times-Roman new file mode 100644 index 0000000000..67172c8d9b Binary files /dev/null and b/fonts/Times-Roman differ diff --git a/fonts/Utopia-Bold b/fonts/Utopia-Bold new file mode 100644 index 0000000000..06b91085a4 Binary files /dev/null and b/fonts/Utopia-Bold differ diff --git a/fonts/Utopia-BoldItalic b/fonts/Utopia-BoldItalic new file mode 100644 index 0000000000..c36689694d Binary files /dev/null and b/fonts/Utopia-BoldItalic differ diff --git a/fonts/Utopia-Italic b/fonts/Utopia-Italic new file mode 100644 index 0000000000..e33f16af90 Binary files /dev/null and b/fonts/Utopia-Italic differ diff --git a/fonts/Utopia-Regular b/fonts/Utopia-Regular new file mode 100644 index 0000000000..1772a3a0b7 Binary files /dev/null and b/fonts/Utopia-Regular differ diff --git a/fonts/ZapfChancery-MediumItalic b/fonts/ZapfChancery-MediumItalic new file mode 100644 index 0000000000..a8a97002d4 Binary files /dev/null and b/fonts/ZapfChancery-MediumItalic differ diff --git a/fonts/ZapfDingbats b/fonts/ZapfDingbats new file mode 100644 index 0000000000..eaf7105c80 Binary files /dev/null and b/fonts/ZapfDingbats differ diff --git a/locale/C/cups_C b/locale/C/cups_C new file mode 100644 index 0000000000..dc69f651ca --- /dev/null +++ b/locale/C/cups_C @@ -0,0 +1,123 @@ +us-ascii +OK +Cancel +Help +Quit +Close +Yes +No +On +Off +Save +Discard +Default +Options +More Info +Black +Color +Cyan +Magenta +Yellow +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +General +Printer +Image Options +HP-GL/2 Options +Extra +Document +Other +Print Pages: +Entire Document +Page Range: +Reverse Order: +Page Format: + 1-Up + 2-Up + 4-Up +Image Scaling: +Use Natural Image Size +Zoom by Percent +Zoom by PPI +Mirror Image: +Color Saturation: +Color Hue: +Fit to Page: +Shading: +Pen Width: +Gamma Correction: +Brightness: +Add +Delete +Modify +Printer URI +Printer Name +Printer Location +Printer Info +Printer Make and Model +Device URI +Formatting Page +Printing Page +Initializing Printer +Printer State +Accepting Jobs +Not Accepting Jobs +Print Jobs +Class +Local +Remote +Duplexing +Stapling +Fast Copies +Collated Copies +Hole Punching +Covering +Binding +Sorting +Small (up to 9.5x14in) +Medium (9.5x14in to 13x19in) +Large (13x19in and larger) +Custom Size +Idle +Processing +Stopped +All +Odd +Even Pages +Darker Lighter +Media Size +Media Type +Media Source +Orientation: +Portrait +Landscape +Job State +Job Name +User Name +Priority +Copies +File Size +Pending +Output Mode +Resolution +400 Your browser sent a request that this server could not understand. +This server could not verify that you are authorized to access the resource. +You must pay to access this server. +You don't have permission to access the resource on this server. +The requested resource was not found on this server. +The requested method is not allowed with the resource. +An appropriate representation for the resource was not found on this server. +You don't have permission to use this server as a proxy host. +The request has taken too long to complete and has been aborted. +The requested resource has more than one value. +The requested resource is gone and has not been replaced. +The requested method requires a valid Content-Length. +The precondition on the request evaluated to false. +The request is too large for this server to process. +The request URI is too large for this server to process. +The request format is not understood by this server. +500 The server has detected an unrecoverable error and cannot process your request. +The requested method is not implemented by this server. +The proxy server received an invalid response from an upstream server. +The requested resource is currently unavailable on this server. +The proxy server has taken too long to respond to this server. +This server does not support the HTTP version required by your browser. diff --git a/locale/Makefile b/locale/Makefile new file mode 100644 index 0000000000..06ab0ab1f3 --- /dev/null +++ b/locale/Makefile @@ -0,0 +1,73 @@ +# +# "$Id$" +# +# Locale file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Locales... +# + +LOCALES = C de en es fr it + +# +# Make everything... +# + +all: translate + +# +# Clean all config and object files... +# + +clean: + +# +# Install files... +# + +install: + -$(MKDIR) $(LIBDIR)/locale + for dir in $(LOCALES) ; do \ + if test ! -d $(LIBDIR)/locale/$$dir ; then \ + $(MKDIR) $(LIBDIR)/locale/$$dir ; \ + fi ; \ + $(CP) cups_$$dir $(LIBDIR)/locale/$$dir ; \ + done + +# +# translate - a simple utility to use Bablefish to translate the POSIX message +# file to one of several languages. +# +# translate outfile language +# + +translate: translate.o ../cups/libcups.a + echo Linking $<... + $(CC) $(LDFLAGS) -o translate translate.o $(LIBS) + +translate.o: ../cups/http.h + +# +# End of "$Id$". +# diff --git a/locale/de/cups_de b/locale/de/cups_de new file mode 100644 index 0000000000..7a387cec7a --- /dev/null +++ b/locale/de/cups_de @@ -0,0 +1,123 @@ +iso-8859-1 +OK +Löschen +Hilfe +Beendet +Nah +Ja +Nein +Auf +Weg von +Außer +Ausschuß +Rückstellung +Optionen +Mehr INFO +Schwarzes +Farbe +Cyan-blau +Magenta +Gelb +Copyright 1993-1999 durch Easy Software Products, alle Rechte vorbehalten. +General +Drucker +BildOptionen +HP-GL/2 Optionen +Extrakosten +Dokument +Anderes +DruckSeiten: +Gesamtes Dokument +Seitenbereich: +RückOrdnung: +Seite Format: + 1-Up + 2-Up + 4-Up +BildScaling: +Natürliche BildGröße Des Gebrauches +Zoom durch Percent +Zoom durch PPI +SpiegelBild: +Farbe Sättigung: +Farbe Farbe: +Passen Sie, um zu paginieren: +Schattierend: +FederBreite: +Gamma Korrektur: +Helligkeit: +Fügen Sie hinzu +Löschung +ändern Sie +DruckerURI +DruckerName +DruckerStandort +Drucker-cInfo +Drucker bilden und formen +EinheitURI +Formatierung Seite +Seite Druckend +InitialisierenDrucker +DruckerZustand +Jobs Annehmend +Jobs Nicht, Annehmend +Druckjobs +Kategorie +Lokal +Entfernte Station +Duplexing +Heftend +Schnelle Plattenkopierprogramme +Gemischte Exemplare +Bohrung Lochen +Bedeckung +Binden +Sortierend +Klein (bis 9.5x1în) +Medium (9.5x1în bis 13x19in) +Groß (13x19in und größeres) +Kundenspezifische Größe +Leerlauf +Verarbeitend +Gestoppt +Alles +Ungerade +Gleichmäßige Seiten +Dunkleres Heller +MediaGröße +MediaArt +MediaQuelle +Lagebestimmung: +Portrait +Landschaft +Job State +Job Name +User Name +Priority +Copies +File Size +Pending +Output Mode +Resolution +400 Ihre Datenbanksuchroutine sendete einen Antrag, den dieser Server nicht verstehen könnte. +Dieser Server könnte nicht überprüfen, daß Sie autorisiert sind, das Hilfsmittel zuzugreifen. +Sie müssen zahlen, diesen Server zuzugreifen. +Sie haben nicht Erlaubnis, das Hilfsmittel auf diesem Server zuzugreifen. +Das erbetene Hilfsmittel wurde nicht auf diesem Server gefunden. +Die erbetene Methode wird nicht mit dem Hilfsmittel erlaubt. +Eine passende Darstellung für das Hilfsmittel wurde nicht auf diesem Server gefunden. +Sie haben nicht Erlaubnis, diesen Server als Proxyhauptrechner zu benutzen. +Der Antrag hat zu lang genommen, um durchzuführen und ist abgebrochen worden. +Das erbetene Hilfsmittel hat mehr als einen Wert. +Das erbetene Hilfsmittel wird gegangen und ist nicht ersetzt worden. +Die erbetene Methode benötigt ein gültiges Content-Length. +Die Vorbedingung auf dem Antrag wertete zu falschem aus. +Der Antrag ist zu groß, damit dieser Server verarbeitet. +Der AntragcUri ist zu groß, damit dieser Server verarbeitet. +Das Antragformat wird nicht durch diesen Server verstanden. +500 Der Server hat einen unrecoverable Fehler ermittelt und nicht Ihren Antrag verarbeiten kann. +Die erbetene Methode wird nicht durch diesen Server eingeführt. +Das proxy server empfing eine unzulässige Antwort von einem aufwärts gerichteten Server. +Das erbetene Hilfsmittel ist aktuell auf diesem Server nicht erreichbar. +Das proxy server hat zu lang genommen, um auf diesen Server zu reagieren. +Dieser Server unterstützt nicht die HTTP-Version, die durch Ihre Datenbanksuchroutine angefordert wird. diff --git a/locale/en/cups_en b/locale/en/cups_en new file mode 100644 index 0000000000..de5472dbb9 --- /dev/null +++ b/locale/en/cups_en @@ -0,0 +1,123 @@ +iso-8859-1 +OK +Cancel +Help +Quit +Close +Yes +No +On +Off +Save +Discard +Default +Options +More Info +Black +Colour +Cyan +Magenta +Yellow +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +General +Printer +Image Options +HP-GL/2 Options +Extra +Document +Other +Print Pages: +Entire Document +Page Range: +Reverse Order: +Page Format: + 1-Up + 2-Up + 4-Up +Image Scaling: +Use Natural Image Size +Zoom by Percent +Zoom by PPI +Mirror Image: +Colour Saturation: +Colour Hue: +Fit to Page: +Shading: +Pen Width: +Gamma Correction: +Brightness: +Add +Delete +Modify +Printer URI +Printer Name +Printer Location +Printer Info +Printer Make and Model +Device URI +Formatting Page +Printing Page +Initializing Printer +Printer State +Accepting Jobs +Not Accepting Jobs +Print Jobs +Class +Local +Remote +Duplexing +Stapling +Fast Copies +Collated Copies +Hole Punching +Covering +Binding +Sorting +Small (up to 9.5x14in) +Medium (9.5x14in to 13x19in) +Large (13x19in and larger) +Custom Size +Idle +Processing +Stopped +All +Odd +Even Pages +Darker Lighter +Media Size +Media Type +Media Source +Orientation: +Portrait +Landscape +Job State +Job Name +User Name +Priority +Copies +File Size +Pending +Output Mode +Resolution +400 Your browser sent a request that this server could not understand. +This server could not verify that you are authorized to access the resource. +You must pay to access this server. +You don't have permission to access the resource on this server. +The requested resource was not found on this server. +The requested method is not allowed with the resource. +An appropriate representation for the resource was not found on this server. +You don't have permission to use this server as a proxy host. +The request has taken too long to complete and has been aborted. +The requested resource has more than one value. +The requested resource is gone and has not been replaced. +The requested method requires a valid Content-Length. +The precondition on the request evaluated to false. +The request is too large for this server to process. +The request URI is too large for this server to process. +The request format is not understood by this server. +500 The server has detected an unrecoverable error and cannot process your request. +The requested method is not implemented by this server. +The proxy server received an invalid response from an upstream server. +The requested resource is currently unavailable on this server. +The proxy server has taken too long to respond to this server. +This server does not support the HTTP version required by your browser. diff --git a/locale/es/cups_es b/locale/es/cups_es new file mode 100644 index 0000000000..0971aa5524 --- /dev/null +++ b/locale/es/cups_es @@ -0,0 +1,123 @@ +iso-8859-1 +OK +Cancelación +Ayuda +Salido +Cercano +Sí +No +En +De +Excepto +Descarte +Valor por defecto +Opciones +Más Info +Negro +Color +Ciánico +Magenta +Amarillo +El copyright 1993-1999 por Easy Software Products, todos endereza reservado. +General +Impresora +Opciones De la Imagen +Opciones De HP-GL/2 +Suplemento +Documento +Otro +Paginaciones De la Impresión: +Entero Documento +Rango De Paginación: +Orden Reversa: +Formato De la Paginación: + 1-Up + 2-Up + 4-Up +Escalamiento De la Imagen: +Talla Natural De la Imagen Del Uso +Zoom de Percent +Zoom de PPI +Imagen Del Espejo: +Saturación Del Color: +Tonalidad Del Color: +Quepa para paginar: +Sombreando: +Anchura De la Pluma: +Corrección Gamma: +Brillo: +Agregue +Cancelación +Modifiqúese +URI De la Impresora +Nombre De la Impresora +Localización De la Impresora +Impresora Info +La impresora hace y modela +URI Del Dispositivo +Paginación Del Formato +Imprimiendo La Paginación +De Incialización Impresora +Estado De la Impresora +Validando Trabajos +No validando Trabajos +Trabajos De Impresión +Clase +Local +Telecontrol +Duplexing +Sujetando con grapa +Rápidas Copias +Clasificadas Copias +Perforación Del Agujero +Cubierta +Atando +Clasificando +Pequeño (los hasta 9.5x14in) +Media (los 9.5x14in a el 13x19in) +Grande (el 13x19in y más grande) +De encargo Talla +Marcha lenta +Procesando +Parado +Todo +Impar +Uniformes Paginaciones +Más Oscuro Más Brillante +Talla De Media +Tipo De Media +Fuente De los Media +Orientación: +Retrato +Paisaje +Job State +Job Name +User Name +Priority +Copies +File Size +Pending +Output Mode +Resolution +400 Su browser envió una petición que este servidor no podría entender. +Este servidor no podría verificar que le autoricen a tener acceso al recurso. +Usted debe pagar tener acceso a este servidor. +Usted no tiene permiso de tener acceso al recurso en este servidor. +El recurso solicitado no fue encontrado en este servidor. +El método solicitado no se permite con el recurso. +Una representación apropiada para el recurso no fue encontrada en este servidor. +Usted no tiene permiso de utilizar este servidor como ordenador principal del poder. +La petición ha durado demasiado para terminar y se ha abortado. +El recurso solicitado tiene más de un valor. +Se va y no se ha substituido el recurso solicitado. +El método solicitado requiere un Content-Length válido. +La condición previa en la petición evaluó a falso. +La petición es demasiado grande para que este servidor procese. +El URI de la petición es demasiado grande para que este servidor procese. +El formato de la petición no es entendido por este servidor. +500 El servidor ha detectado un error irrecuperable y no puede procesar su petición. +El método solicitado no es puesto en ejecución por este servidor. +El proxy server recibió una respuesta inválida de un servidor por aguas arriba. +El recurso solicitado es actualmente inasequible en este servidor. +El proxy server ha durado demasiado para responder a este servidor. +Este servidor no utiliza la versión del HTTP requerida por su browser. diff --git a/locale/fr/cups_fr b/locale/fr/cups_fr new file mode 100644 index 0000000000..fa5c05924f --- /dev/null +++ b/locale/fr/cups_fr @@ -0,0 +1,123 @@ +iso-8859-1 +OK +Annulation +Aide +Quitté +Étroit +Oui +Non +Sur +Outre de +Économiser +Écart +Défaut +Options +Plus D'Information +Noir +Couleur +Cyan +Magenta +Jaune +Copyright 1993-1999 par Easy Software Products, tous droits réservés. +Général +Imprimante +Options D'Image +Options D'HP-GL/2 +Frais supplémentaires +Document +Autre +Pages D'Impression: +Entier Document +Chaîne De Page +Commande D'Inversion: +Format De Page: + 1-Up + 2-Up + 4-Up +Graduation D'Image: +Taille Normale D'Image D'Utilisation +Zoom par Percent +Zoom par PPI +Image De Miroir: +Saturation De Couleur: +Tonalité De Couleur: +Adaptez pour paginer: +Ombrageant: +Largeur De Crayon lecteur: +Gamma Correction: +Éclat: +Ajoutez +Effacement +Modifiez +URI D'Imprimante +Nom D'Imprimante +Emplacement D'Imprimante +Information D'Imprimante +L'imprimante font et modèlent +URI De Dispositif +Page De Formatage +Imprimant La Page +D' Initialisation Imprimante +État D'Imprimante +Recevant Les Travaux +Ne recevant pas Les Travaux +Tirages +Classe +Local +Périphérique +Duplexage +Agrafant +Rapides Copies +Assemblées Copies +Poinçon De Trou +Bâche +Liant +Triant +Petit (jusqu'à 9.5x1în) +Support (9.5x1în à 13x19in) +Grand (13x19in et plus grand) +Faite sur commande Taille +Ralenti +Traitant +Arrêté +Tout +Impair +Même Pages +Plus foncé Plus Lumineux +Taille De Medias +Type De Supports +Source De Medias +Orientation: +Verticale +Horizontal +Job State +Job Name +User Name +Priority +Copies +File Size +Pending +Output Mode +Resolution +400 Votre browser a envoyé une demande que ce serveur ne pourrait pas comprendre. +Ce serveur ne pourrait pas vérifier que vous êtes autorisés à accéder à la ressource. +Vous devez payer pour accéder à ce serveur. +Vous n'avez pas la permission d'accéder à la ressource sur ce serveur. +La ressource demandée n'a pas été trouvée sur ce serveur. +On ne permet pas la méthode demandée avec la ressource. +Une représentation appropriée pour la ressource n'a pas été trouvée sur ce serveur. +Vous n'avez pas la permission d'utiliser ce serveur comme centre serveur de procuration. +La demande a pris trop longtemps pour se terminer et a été interrompue. +La ressource demandée a plus d'une valeur. +La ressource demandée est allée et n'a pas été substituée. +La méthode demandée exige un Content-Length valide. +La condition préalable sur la demande a évalué à faux. +La demande est trop grande pour que ce serveur traite. +L'cUri de demande est trop grand pour que ce serveur traite. +Le format de demande n'est pas compris par ce serveur. +500 Le serveur a détecté une erreur irrémédiable et ne peut pas traiter votre demande. +La méthode demandée n'est pas appliquée par ce serveur. +Le proxy server a reçu une réponse incorrecte d'un serveur ascendant. +La ressource demandée est actuel indisponible sur ce serveur. +Le proxy server a pris trop longtemps pour répondre à ce serveur. +Ce serveur ne supporte pas la version de HTTP exigée par votre browser. diff --git a/locale/it/cups_it b/locale/it/cups_it new file mode 100644 index 0000000000..228c6a8357 --- /dev/null +++ b/locale/it/cups_it @@ -0,0 +1,123 @@ +iso-8859-1 +GIUSTO +Annullamento +Aiuto +Rinunciato +Vicino +Sì +No +Su +Fuori di +Risparmi +Scarto +Difetto +Opzioni +Più Info +Nero +Colore +Ciano +Fucsina +Colore giallo +Copyright 1993-1999 da di Easy Software Products, tutti radrizza riservato. +Generalità +Stampante +Opzioni Di Immagine +Opzioni Di HP-GL/2 +Supplemento +Documento +Altro +Pagine Della Stampa: +Intero Documento +Gamma Di Pagina: +Ordine D'inversione: +Formato Della Pagina: + 1-Up + 2-Up + 4-Up +Scaling Di Immagine: +Formato Naturale Di Immagine Di Uso +Zoom da Percent +Zoom da PPI +Immagine Dello Specchio: +Saturazione Di Colore: +Tonalità Di Colore: +Adattare per paginare: +Proteggendo: +Larghezza Della Penna: +Correzione Gamma: +Luminosità: +Aggiungere +Cancellazione +Modificare +URI Della Stampante +Nome Della Stampante +Posizione Della Stampante +Stampante Info +Stampante fa e modella +URI Del Dispositivo +Pagina Di Formattazione +Stampando Pagina +D' Inizializzazione Stampante +Condizione Della Stampante +Accettando I Lavori +Non accettando I Lavori +Lavori Di Stampa +Codice categoria +Locale +Periferico +Utilizzazione per due usi +Cucendo con punti metallici +Veloci Copie +Fascicolate Copie +Perforazione Del Foro +Covering +Legandosi +Ordinando +Piccolo (fino a 9.5x1în) +Media (9.5x1în - 13x19in) +Grande (13x19in e più grande) +Su ordinazione Formato +Idle +Elaborando +Arrestato +Tutto +Dispari +Anche Pagine +Più Scuro Più Luminoso +Formato Di Media +Tipo Di Media +Sorgente Di Media +Orientamento: +Portrait +Paesaggio +Job State +Job Name +User Name +Priority +Copies +File Size +Pending +Output Mode +Resolution +400 Il vostro browser ha trasmesso una richiesta che questo server non potrebbe capire. +Questo server non potrebbe verificare che siete autorizzati ad accedere alla risorsa. +Dovete pagare accedere a questo server. +Non avete permesso accedere alla risorsa su questo server. +La risorsa chiesta non è stata trovata su questo server. +Il metodo chiesto non è permesso con la risorsa. +Una rappresentazione adatta per la risorsa non è stata trovata su questo server. +Non avete permesso utilizzare questo server come calcolatore centrale di procura. +La richiesta ha preso troppo lungamente per completare ed è stata abbandonata. +La risorsa chiesta ha più di un valore. +La risorsa chiesta è andata e non è stata sostituita. +Il metodo chiesto richiede un Content-Length valido. +Il presupposto sulla richiesta ha valutato a falso. +La richiesta è troppo grande affinchè questo server elabori. +Il URI di richiesta è troppo grande affinchè questo server elabori. +Il formato di richiesta non è capito da questo server. +500 Il server ha rilevato un errore unrecoverable e non può elaborare la vostra richiesta. +Il metodo chiesto non è effettuato da questo server. +Il proxy server ha ricevuto una risposta non valida da un server verso l'alto. +La risorsa chiesta è attualmente non disponibile su questo server. +Il proxy server ha preso troppo lungamente per rispondere a questo server. +Questo server non sostiene la versione del HTTP richiesta dal vostro browser. diff --git a/locale/locale.txt b/locale/locale.txt new file mode 100644 index 0000000000..f9abe72d67 --- /dev/null +++ b/locale/locale.txt @@ -0,0 +1,32 @@ +This directory contains the message strings used by CUPS for various +languages. Each subdirectory corresponds to a different locale, and +the cups_xx and cups_xx_YY files contain the messages for the locales +named "xx" or "xx_YY". + +Each message file starts with a character set identifier, which can be +one of the following: + + us-ascii + iso-8859-1 + iso-8859-2 + iso-8859-3 + iso-8859-4 + iso-8859-5 + iso-8859-6 + iso-8859-7 + iso-8859-8 + iso-8859-9 + utf-8 + +After that, all non-blank lines are treated as messages, with any +leading whitespace removed. If a line starts with a number then the +message index is updated to the number. Otherwise, the next message +number is used. + +The message indices are defined in the include file . +The HTTP status messages use the status codes defined in . + +If you would like to contribute a new message file for your locale, or +have corrections to the current ones, please send them to: + + cups-support@cups.org diff --git a/locale/translate.c b/locale/translate.c new file mode 100644 index 0000000000..e56690be62 --- /dev/null +++ b/locale/translate.c @@ -0,0 +1,259 @@ +/* + * "$Id$" + * + * HTTP-based translation program for the Common UNIX Printing System (CUPS). + * + * This program uses AltaVista's "babelfish" page to translate the POSIX + * message file (C/cups_C) to several different languages. The translation + * isn't perfect, but it's a good start (better than working from scratch.) + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44145 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include + +#include + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + http_t *http; /* HTTP connection */ + http_status_t status; /* Status of GET command */ + char line[1024], /* Line from file */ + *lineptr, /* Pointer into line */ + buffer[2048], /* Input/output buffer */ + *bufptr, /* Pointer into buffer */ + length[16]; /* Content length */ + int bytes; /* Number of bytes read */ + FILE *in, /* Input file */ + *out; /* Output file */ + + + if (argc != 3) + { + fputs("Usage: translate outfile language\n", stderr); + return (1); + } + + if ((in = fopen("C/cups_C", "r")) == NULL) + { + perror("translate: Unable to open input file"); + return (1); + } + + if ((out = fopen(argv[1], "w")) == NULL) + { + perror("translate: Unable to create output file"); + fclose(in); + return (1); + } + + /* + * Do character set... + */ + + fgets(line, sizeof(line), in); + fputs("iso-8859-1\n", out); /* Right now that's all that Babelfish does */ + + /* + * Then strings... + */ + + while (fgets(line, sizeof(line), in) != NULL) + { + /* + * Strip trailing newline if necessary... + */ + + lineptr = line + strlen(line) - 1; + if (*lineptr == '\n') + *lineptr = '\0'; + + /* + * Skip leading numbers and whitespace... + */ + + lineptr = line; + while (isdigit(*lineptr)) + putc(*lineptr++, out); + + while (isspace(*lineptr)) + putc(*lineptr++, out); + + if (*lineptr == '\0') + { + putc('\n', out); + continue; + } + + /* + * Encode the line into the buffer... + */ + + sprintf(buffer, "doit=done&lp=en_%s&urltext=[", argv[2]); + bufptr = buffer + strlen(buffer); + + while (*lineptr) + { + if (*lineptr == ' ') + *bufptr++ = '+'; + else if (*lineptr < ' ' || *lineptr == '%') + { + sprintf(bufptr, "%%%02X", *lineptr & 255); + bufptr += 3; + } + else + *bufptr++ = *lineptr; + + lineptr ++; + } + + *bufptr++ = '&'; + *bufptr = '\0'; + + sprintf(length, "%d", bufptr - buffer); + + /* + * Send the request... + */ + + if ((http = httpConnect("dns.easysw.com", 80)) == NULL) + { + perror("translate: Unable to contact proxy server"); + fclose(in); + fclose(out); + return (1); + } + + lineptr = line; + while (isdigit(*lineptr)) + lineptr ++; + while (isspace(*lineptr)) + lineptr ++; + + printf("%s = ", lineptr); + fflush(stdout); + + http->version = HTTP_1_0; + httpClearFields(http); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, + "application/x-www-form-urlencoded"); + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); + if (httpPost(http, "http://babelfish.altavista.digital.com/cgi-bin/translate?")) + httpPost(http, "http://babelfish.altavista.digital.com/cgi-bin/translate?"); + + httpWrite(http, buffer, bufptr - buffer); + + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + + if (status == HTTP_OK) + { + int sawparen = 0; + int skipws = 1; + int sawbracket = 0; + + while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0) + { + buffer[bytes] = '\0'; + + for (bufptr = buffer; *bufptr; bufptr ++) + { + if (*bufptr == '>') + sawbracket = 0; + else if (*bufptr == '<') + { + sawbracket = 1; + if (sawparen) + break; + } + else if (*bufptr == '[' && !sawbracket) + sawparen = 1; + else if (sawparen) + { + if (skipws) + { + if (!isspace(*bufptr)) + { + skipws = 0; + *bufptr = toupper(*bufptr); + } + } + + if (!skipws) + { + if (*bufptr == '\n') + { + putc(' ', out); + putchar(' '); + } + else + { + putc(*bufptr, out); + putchar(*bufptr); + } + } + } + } + + if (sawparen && sawbracket) + break; + } + + httpFlush(http); + putc('\n', out); + putchar('\n'); + } + else + { + printf("HTTP error %d\n", status); + + fprintf(out, "%s\n", lineptr); + httpFlush(http); + } + + httpClose(http); + } + + fclose(in); + fclose(out); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/man/Makefile b/man/Makefile new file mode 100644 index 0000000000..55c2fbe9fd --- /dev/null +++ b/man/Makefile @@ -0,0 +1,78 @@ +# +# "$Id$" +# +# Man page makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Man pages... +# + +MAN1 = backend.1 filter.1 lprm.1 lpr.1 lpstat.1 lp.1 +MAN5 = classes.conf.5 cupsd.conf.5 mime.convs.5 mime.types.5 \ + printers.conf.5 +MAN8 = accept.8 cupsd.8 enable.8 lpadmin.8 lpc.8 + +CAT1 = $(MAN1:.1=.$(CAT)) +CAT5 = $(MAN5:.5=.$(CAT)) +CAT8 = $(MAN8:.8=.$(CAT)) + +# +# Make everything... +# + +all: $(CAT1) $(CAT5) $(CAT8) + +# +# Clean all config and object files... +# + +clean: + +# +# Install files... +# + +install: + -$(MKDIR) $(MANDIR)/man1 + $(CP) $(MAN1) $(MANDIR)/man1 + $(LN) lp.1 $(MANDIR)/man1/cancel.1 + -$(MKDIR) $(MANDIR)/man5 + $(CP) $(MAN5) $(MANDIR)/man5 + -$(MKDIR) $(MANDIR)/man8 + $(CP) $(MAN8) $(MANDIR)/man8 + $(LN) accept.8 $(MANDIR)/man8/reject.8 + $(LN) enable.8 $(MANDIR)/man8/disable.8 + -$(MKDIR) $(MANDIR)/cat1 + $(CP) $(CAT1) $(MANDIR)/cat1 + $(LN) lp.$(CAT) $(MANDIR)/cat1/cancel.$(CAT) + -$(MKDIR) $(MANDIR)/cat5 + $(CP) $(CAT5) $(MANDIR)/cat5 + -$(MKDIR) $(MANDIR)/cat8 + $(CP) $(CAT8) $(MANDIR)/cat8 + $(LN) accept.$(CAT) $(MANDIR)/cat8/reject.$(CAT) + $(LN) enable.$(CAT) $(MANDIR)/cat8/disable.$(CAT) + +# +# End of "$Id$". +# diff --git a/man/accept.8 b/man/accept.8 new file mode 100644 index 0000000000..fa379027fb --- /dev/null +++ b/man/accept.8 @@ -0,0 +1,57 @@ +.\" +.\" "$Id: accept.8 380 1999-06-10 16:15:04Z mike $" +.\" +.\" accept/reject man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH accept 8 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +accept/reject \- accept/reject jobs sent to a destination +.SH SYNOPSIS +.B accept +destination(s) +.br +.B reject +[ -h +.I server +] [ -r [ +.I reason +] ] +destination(s) +.SH DESCRIPTION +\fBaccept\fR instructs the printing system to accept print jobs to the +specified destinations. +.LP +\fBreject\fR instructs the printing system to reject print jobs to the +specified destinations. The \fI-r\fR option sets the reason for rejecting +print jobs. If not specified the reason defaults to "Reason Unknown". +.SH COMPATIBILITY +The CUPS versions of \fBaccept\fR and \fBreject\fR may ask the user for an +access password depending on the printing system configuration. This differs +from the System V versions which require the root user to execute these +commands. +.SH SEE ALSO +cancel(1), disable(8), enable(8), lp(1), lpadmin(8), lpstat(1), +CUPS Software Administrator's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: accept.8 380 1999-06-10 16:15:04Z mike $". +.\" diff --git a/man/accept.z b/man/accept.z new file mode 100644 index 0000000000..6ec1f4f6c8 Binary files /dev/null and b/man/accept.z differ diff --git a/man/backend.1 b/man/backend.1 new file mode 100644 index 0000000000..6b89cef89e --- /dev/null +++ b/man/backend.1 @@ -0,0 +1,88 @@ +.\" +.\" "$Id: backend.1 327 1999-05-14 17:03:06Z mike $" +.\" +.\" backend man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH backend 1 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +backend \- backend transmission interfaces +.SH SYNOPSIS +.B backend +job user title num-copies options +.I [ filename ] +.SH DESCRIPTION +The CUPS backend interface provides a standard method for sending document +files to different physical interfaces. +.LP +Backends must be capable of reading from a filename on the command-line +or from the standard input, copying stdin to a temporary if required by +the physical interface. +.LP +The command name (argv[0]) is set to the device URI of the destination printer. +.SH ENVIRONMENT VARIABLES +The following environment variables are defined by the CUPS server when +executing the backend: +.TP 5 +CHARSET +.br +The default text character set (typically us-ascii or iso-8859-1). +.TP 5 +LANG +.br +The default language locale (typically C or en). +.TP 5 +PATH +.br +The standard execution path for external programs that may be run by the backend. +.TP 5 +PPD +.br +The full pathname of the PostScript Printer Description (PPD) file for +this printer. +.TP 5 +RIP_CACHE +.br +The recommended amount of memory to use for Raster Image Processors (RIPs). +.TP 5 +SERVER_ROOT +.br +The root directory of the server. +.TP 5 +SOFTWARE +.br +The name and version number of the server (typically CUPS/1.0). +.TP 5 +TZ +.br +The timezone of the server (typically GMT). +.TP 5 +USER +.br +The user executing the backend (typically root). +.SH SEE ALSO +cupsd(8), filter(1) +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: backend.1 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/backend.z b/man/backend.z new file mode 100644 index 0000000000..2baa1b475b Binary files /dev/null and b/man/backend.z differ diff --git a/man/classes.conf.5 b/man/classes.conf.5 new file mode 100644 index 0000000000..5fb42a7b95 --- /dev/null +++ b/man/classes.conf.5 @@ -0,0 +1,36 @@ +.\" +.\" "$Id: classes.conf.5 327 1999-05-14 17:03:06Z mike $" +.\" +.\" classes.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH classes.conf 5 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +classes.conf \- class configuration file for cups +.SH DESCRIPTION +.SH SEE ALSO +cupsd(8), cupsd.conf(5), mime.convs(5), mime.types(5), printers.conf(5), +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: classes.conf.5 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/classes.conf.z b/man/classes.conf.z new file mode 100644 index 0000000000..1d3b5b98f4 Binary files /dev/null and b/man/classes.conf.z differ diff --git a/man/cupsd.8 b/man/cupsd.8 new file mode 100644 index 0000000000..3e81631af4 --- /dev/null +++ b/man/cupsd.8 @@ -0,0 +1,47 @@ +.\" +.\" "$Id: cupsd.8 327 1999-05-14 17:03:06Z mike $" +.\" +.\" cupsd man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cupsd 8 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +cupsd \- common unix printing system daemon +.SH SYNOPSIS +.B cups +.I [ \-c config-file ] +.SH DESCRIPTION +\fBcupsd\fR is the scheduler for the Common UNIX Printing System. It implements +a printing system based upon the Internet Printing Protocol, version 1.0. If +no options are specified on the command-line then the default configuration file +(usually \fI/var/cups/conf/cupsf.conf\fR) will be used. +.SH COMPATIBILITY +\fBcupsd\fR implements all of the required IPP/1.0 attributes and operations. +It also implements optional operation set 1 and several CUPS-specific +administation operations. +.SH SEE ALSO +classes.conf(5), cupsd.conf(5), mime.convs(5), mime.types(5), printers.conf(5), +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupsd.8 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/cupsd.conf.5 b/man/cupsd.conf.5 new file mode 100644 index 0000000000..33d5781c8b --- /dev/null +++ b/man/cupsd.conf.5 @@ -0,0 +1,36 @@ +.\" +.\" "$Id: cupsd.conf.5 327 1999-05-14 17:03:06Z mike $" +.\" +.\" cupsd.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cupsd.conf 5 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +cupsd.conf \- server configuration file for cups +.SH DESCRIPTION +.SH SEE ALSO +classes.conf(5), cupsd(8), mime.convs(5), mime.types(5), printers.conf(5), +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupsd.conf.5 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/cupsd.conf.z b/man/cupsd.conf.z new file mode 100644 index 0000000000..84ac20774b Binary files /dev/null and b/man/cupsd.conf.z differ diff --git a/man/cupsd.z b/man/cupsd.z new file mode 100644 index 0000000000..842424f664 Binary files /dev/null and b/man/cupsd.z differ diff --git a/man/enable.8 b/man/enable.8 new file mode 100644 index 0000000000..4e0d7f4863 --- /dev/null +++ b/man/enable.8 @@ -0,0 +1,64 @@ +.\" +.\" "$Id: enable.8 380 1999-06-10 16:15:04Z mike $" +.\" +.\" enable/disable man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH enable 8 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +disable, disable \- stop/start printers and classes +.SH SYNOPSIS +.B enable +destination(s) +.br +.B disable +[ \-c ] [ -h +.I server +] [ \-r [ +.I reason +] ] destination(s) +.SH DESCRIPTION +\fBenable\fR starts the named printers or classes. +.LP +\fBdisable\fR stops the named printers or classes. The following options may +be used: +.TP 5 +\-c +.br +Cancels all jobs on the named destination. +.TP 5 +\-r [ \fIreason\fR ] +.br +Sets the message associated with the stopped state. If no reason is specified +then the message is set to "Reason Unknown". +.SH COMPATIBILITY +The CUPS versions of \fBdisable\fR and \fBenable\fR may ask the user for an +access password depending on the printing system configuration. This differs +from the System V versions which require the root user to execute these +commands. +.SH SEE ALSO +accept(8), cancel(1), lp(1), lpadmin(8), lpstat(1), reject(8), +CUPS Software Administrator's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. + +.\" +.\" End of "$Id: enable.8 380 1999-06-10 16:15:04Z mike $". +.\" diff --git a/man/enable.z b/man/enable.z new file mode 100644 index 0000000000..f2b4cfd113 Binary files /dev/null and b/man/enable.z differ diff --git a/man/filter.1 b/man/filter.1 new file mode 100644 index 0000000000..51d494d987 --- /dev/null +++ b/man/filter.1 @@ -0,0 +1,95 @@ +.\" +.\" "$Id: filter.1 327 1999-05-14 17:03:06Z mike $" +.\" +.\" filter man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH filter 1 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +filter \- file conversion filter interfaces +.SH SYNOPSIS +.B filter +job user title num-copies options +.I [ filename ] +.SH DESCRIPTION +The CUPS filter interface provides a standard method for adding support for +new document types to CUPS. Each filter is capable of converting from one +or more input formats to another format that can either be printed directly +or piped into another filter to get it to a printable format. +.LP +Filters must be capable of reading from a filename on the command-line or from +the standard input, copying stdin to a temporary if required by the file +format. +.LP +The command name (argv[0]) is set to the name of the destination printer. +.SH ENVIRONMENT VARIABLES +The following environment variables are defined by the CUPS server when +executing each filter: +.TP 5 +CHARSET +.br +The default text character set (typically us-ascii or iso-8859-1). +.TP 5 +LANG +.br +The default language locale (typically C or en). +.TP 5 +PATH +.br +The standard execution path for external programs that may be run by the filter. +.TP 5 +PPD +.br +The full pathname of the PostScript Printer Description (PPD) file for +this printer. +.TP 5 +RIP_CACHE +.br +The recommended amount of memory to use for Raster Image Processors (RIPs). +.TP 5 +SERVER_ROOT +.br +The root directory of the server. +.TP 5 +SOFTWARE +.br +The name and version number of the server (typically CUPS/1.0). +.TP 5 +TZ +.br +The timezone of the server (typically GMT). +.TP 5 +USER +.br +The user executing the filter (typically root). +.SH COMPATIBILITY +While the filter interface is compatible with System V interface +scripts, it will only work with the System V interface script as the +only filter. Typically the interface script will be provided via the +\fBlpadmin(8)\fR command using the \fI-i\fR option. +.SH SEE ALSO +backend(1), cupsd(8), +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: filter.1 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/filter.z b/man/filter.z new file mode 100644 index 0000000000..44203947c5 Binary files /dev/null and b/man/filter.z differ diff --git a/man/lp.1 b/man/lp.1 new file mode 100644 index 0000000000..57dfb52e80 --- /dev/null +++ b/man/lp.1 @@ -0,0 +1,71 @@ +.\" +.\" "$Id: lp.1 491 1999-07-07 14:03:48Z mike $" +.\" +.\" lp/cancel man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lp 1 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +lp \- print files +.br +cancel \- cancel jobs +.SH SYNOPSIS +.B lp +[ \-c ] [ \-d +.I destination +] [ \-m ] [ \-n +.I num-copies +[ \-o +.I option +] [ \-p/q +.I priority +] [ \-s ] [ \-t +.I title +] [ +.I file(s) +] +.br +.B cancel +[ \-a ] [ -h +.I server +] [ +.I id +] [ +.I destination +] [ +.I destination-id +] +.SH DESCRIPTION +\fBlp\fR submits files for printing. +.LP +\fBcancel\fR cancels existing print jobs. The \fI-a\fR option will remove +all jobs from the specified destination. +.SH COMPATIBILITY +Unlike the System V printing system, CUPS allows printer names to contain +any printable character except SPACE and TAB. Also, printer and class names are +\fBnot\fR case-sensitive. +.SH SEE ALSO +lpstat(1), +CUPS Software User's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lp.1 491 1999-07-07 14:03:48Z mike $". +.\" diff --git a/man/lp.z b/man/lp.z new file mode 100644 index 0000000000..1d45c15750 Binary files /dev/null and b/man/lp.z differ diff --git a/man/lpadmin.8 b/man/lpadmin.8 new file mode 100644 index 0000000000..fc492b1f88 --- /dev/null +++ b/man/lpadmin.8 @@ -0,0 +1,124 @@ +.\" +.\" "$Id: lpadmin.8 461 1999-06-24 17:44:19Z mike $" +.\" +.\" lpadmin man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpadmin 8 "Common UNIX Printing System" "22 June 1999" "Easy Software Products" +.SH NAME +lpadmin \- configure cups printers and classes +.SH SYNOPSIS +.B lpadmin +[ -h +.I server +] \-d +.I destination +.br +.B lpadmin +[ -h +.I server +] \-p +.I printer +.I option(s) +.br +.B lpadmin +[ -h +.I server +] \-x +.I destination +.SH DESCRIPTION +\fBlpadmin\fR configures printer and class queues provided by CUPS. It can also +be used to set the system default printer or class. +.LP +The first form of the command sets the default printer or class to +\fIdestination\fR. Subsequent print jobs submitted via the \fIlp(1)\fR or +\fIlpr(1)\fR commands will use this destination unless the user specifies +otherwise. +.LP +The second form of the command configures the named printer. The additional +options are described below. +.LP +The third form of the command deletes the printer or class \fIdestination\fR. +Any jobs that are pending for the destination will be removed and any job that +is currently printed will be aborted. +.SH CONFIGURATION OPTIONS +The following options are recognized when configuring a printer queue: +.TP 5 +\-c \fIclass\fR +.br +Adds the named \fIprinter\fR to \fIclass\fR. If \fIclass\fR does not +exist it is created automatically. +.TP 5 +\-i \fIinterface\fR +.br +Sets a System V style interface script for the printer. This option cannot +be specified with the \fI\-P\fR option (PPD file) and is intended for +providing support for legacy printer drivers. +.TP 5 +\-m \fImodel\fR +.br +Sets a standard System V interface script or PPD file from the model +directory. +.TP 5 +\-r \fIclass\fR +.br +Removes the named \fIprinter\fR from \fIclass\fR. If the resulting class +becomes empty it is removed. +.TP 5 +\-v \fIdevice-uri\fR +.br +Sets the \fIdevice-uri\fR attribute of the printer queue. If \fIdevice-uri\fR +is a filename it is automatically converted to the form \fBfile:/file/name\fR. +.TP 5 +\-D \fIinfo\fR +.br +Provides a textual description of the printer. +.TP 5 +\-E +.br +Enables the printer; this is the same as running the \fIaccept(8)\fR and +\fIenable(8)\fR programs on the printer. +.TP 5 +\-L \fIlocation\fR +.br +Provides a textual location of the printer. +.TP 5 +\-P \fIppd-file\fR +.br +Specifies a PostScript Printer Description file to use with the printer. If +specified, this option overrides the \fI-i\fR option (interface script). +.SH COMPATIBILITY +Unlike the System V printing system, CUPS allows printer names to contain +any printable character except SPACE and TAB. Also, printer and class names are +\fBnot\fR case-sensitive. Finally, the CUPS version of \fBlpadmin\fR may ask the +user for an access password depending on the printing system configuration. +This differs from the System V version which requires the root user to execute +this command. +.SH LIMITATIONS +The CUPS version of \fBlpadmin\fR does not support all of the System V or +Solaris printing system configuration options. +.SH SEE ALSO +accept(8), cancel(1), disable(8), enable(8), lp(1), lpstat(1), reject(8), +CUPS Software Administrator's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpadmin.8 461 1999-06-24 17:44:19Z mike $". +.\" diff --git a/man/lpadmin.z b/man/lpadmin.z new file mode 100644 index 0000000000..c7b0c61cb4 Binary files /dev/null and b/man/lpadmin.z differ diff --git a/man/lpc.8 b/man/lpc.8 new file mode 100644 index 0000000000..0ce5029d99 --- /dev/null +++ b/man/lpc.8 @@ -0,0 +1,79 @@ +.\" +.\" "$Id: lpc.8 327 1999-05-14 17:03:06Z mike $" +.\" +.\" lpc man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpc 8 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +lpc \- line printer control program +.SH SYNOPSIS +.B lpc +[ +.I command +[ +.I parameter(s) +] ] +.SH DESCRIPTION +\fBlpc\fR provides limited control over printer and class queues provided by +CUPS. It can also be used to query the state of queues. +.LP +If no command is specified on the command-line, \fRlpc\fR will display a +prompt and accept commands from the standard input. +.SH COMMANDS +The \fBlpc\fR program accepts a subset of commands accepted by the Berkeley +\fBlpc\fR program of the same name: +.TP 5 +\fIexit +.br +Exits the command interpreter. +.TP 5 +help \fI[command]\fR +.br +Displays a short help message. +.TP 5 +quit +.br +Exits the command interpreter. +.TP 5 +status \fI[queue]\fR +.br +Displays the status of one or more printer or class queues. +.TP 5 +? \fI[command]\fR +.br +Display a short help message. +.SH LIMITATIONS +Since \fBlpc\fR is geared towards the Berkeley printing system, it is impossible +to use \fBlpc\fR to configure printer or class queues provided by CUPS. To +configure printer or class queues you must use the \fBlpadmin(8)\fR command +or another CUPS-compatible client with that functionality. +.SH COMPATIBILITY +The CUPS version of \fBlpc\fR does not implement all of the standard Berkeley +commands. +.SH SEE ALSO +accept(8), cancel(1), disable(8), enable(8), lp(1), lpr(1), lprm(1), +lpstat(1), reject(8), +CUPS Software Administrator's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpc.8 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/lpc.z b/man/lpc.z new file mode 100644 index 0000000000..9151be9a50 Binary files /dev/null and b/man/lpc.z differ diff --git a/man/lpr.1 b/man/lpr.1 new file mode 100644 index 0000000000..ad563e3ebc --- /dev/null +++ b/man/lpr.1 @@ -0,0 +1,96 @@ +.\" +.\" "$Id: lpr.1 491 1999-07-07 14:03:48Z mike $" +.\" +.\" lpr man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpr 1 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +lpr \- print files +.SH SYNOPSIS +.B lpr +[ \-P +.I destination +] [ \-# +.I num-copies +[ \-l ] [ \-o +.I option +] [ \-p] [ \-r ] [ \-C/J/T +.I title +] [ +.I file(s) +] +.SH DESCRIPTION +\fBlpr\fR submits files for printing. Files named on the command line are sent +to the named printer (or the system default destination if no destination is +specified). If no files are listed on the command-line \fBlpr\fR reads the +print file from the standard input. +.SH OPTIONS +The following options are recognized by \fBlpr\fR: +.TP 5 +\-P \fIdestination\fR +.br +Prints files to the named printer. +.TP 5 +\-# \fIcopies\fR +.br +Sets the number of copies to print from 1 to 100. +.TP 5 +\-C \fIname\fR +.br +Sets the job name. +.TP 5 +\-J \fIname\fR +.br +Sets the job name. +.TP 5 +\-T \fIname\fR +.br +Sets the job name. +.TP 5 +\-l +.br +Specifies that the print file is already formatted for the destination and +should be sent without filtering. This option is equivalent to "-oraw". +.TP 5 +\-o \fIoption\fR +.br +Sets the job name. +.TP 5 +\-p +.br +Specifies that the print file should be formatted with a shaded header with +the date, time, job name, and page number. This option is equivalent to +"-oprettyprint" and is only useful when printing text files. +.TP 5 +\-r +.br +Specifies that the named print files should be deleted after printing them. +.SH COMPATIBILITY +The "c", "d", "f", "g", "i", "m", "n", "t", "v", and "w" options are not +supported by CUPS and will produce a warning message if used. +.SH SEE ALSO +cancel(1), lp(1), lpstat(1), +CUPS Software User's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpr.1 491 1999-07-07 14:03:48Z mike $". +.\" diff --git a/man/lpr.z b/man/lpr.z new file mode 100644 index 0000000000..0a611435ca Binary files /dev/null and b/man/lpr.z differ diff --git a/man/lprm.1 b/man/lprm.1 new file mode 100644 index 0000000000..03b06eb3a5 --- /dev/null +++ b/man/lprm.1 @@ -0,0 +1,40 @@ +.\" +.\" "$Id: lprm.1 327 1999-05-14 17:03:06Z mike $" +.\" +.\" lprm man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lprm 1 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +lprm \- cancel print jobs +.SH SYNOPSIS +.B lprm +.SH DESCRIPTION +\fBlpstat\fR +.SH COMPATIBILITY +SOMETHING +.SH SEE ALSO +cancel(1), lp(1), lpstat(1), +CUPS Software User's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lprm.1 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/lprm.z b/man/lprm.z new file mode 100644 index 0000000000..40f8c05b5d Binary files /dev/null and b/man/lprm.z differ diff --git a/man/lpstat.1 b/man/lpstat.1 new file mode 100644 index 0000000000..e107e5bfa0 --- /dev/null +++ b/man/lpstat.1 @@ -0,0 +1,115 @@ +.\" +.\" "$Id: lpstat.1 461 1999-06-24 17:44:19Z mike $" +.\" +.\" lpstat man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpstat 1 "Common UNIX Printing System" "24 June 1999" "Easy Software Products" +.SH NAME +lpstat \- print cups status information +.SH SYNOPSIS +.B lpstat +[ -a [ +.I destination(s) +] ] [ -c [ +.I class(es) +] ] [ -d ] [ -h +.I server +] [ -o [ +.I destination(s) +] ] [ -p [ +.I printer(s) +] ] [ -r ] [ -s ] [ -t ] [ -u [ +.I user(s) +] ] [ -v [ +.I printer(s) +] ] +.SH DESCRIPTION +\fBlpstat\fR displays status information about the current classes, jobs, and +printers. When run with no arguments, \fBlpstat\fR will list jobs queued by +the user. Other options include: +.TP 5 +\-a [\fIprinter(s)\fR] +.br +Shows the accepting state of printer queues. If no printers are +specified then all printers are listed. +.TP 5 +\-c [\fIclass(es)\fR] +.br +Shows the printer classes and the printers that belong to them. If no +classes are specified then all classes are listed. +.TP 5 +\-d +.br +Shows the current default destination. +.TP 5 +\-h \fIserver\fR +.br +Specifies the CUPS server to communicate with. +.TP 5 +\-o [\fIdestination(s)\fR] +.br +Shows the jobs queue on the specified destinations. If no destinations are +specified all jobs are shown. +.TP 5 +\-p [\fIprinter(s)\fR] +.br +Shows the printers and whether or not they are enabled for printing. If +no printers are specified then all printers are listed. +.TP 5 +\-r +.br +Shows whether or not the CUPS server is running. +.TP 5 +\-s +.br +Shows a status summary, including the system default destination, a +list of classes and their member printers, and a list of printers and +their associated devices. This is equivalent to using the "-d", "-c", +and "-p" options. +.TP 5 +\-t +.br +Shows all status information. This is equivalent to using the "-r", +"-d", "-c", "-d", "-v", "-a", "-p", and "-o" options. +.TP 5 +\-u [\fIuser(s)\fR] +.br +Shows a list of print jobs queued by the specified users. If no users +are specified, lists the jobs queued by the current user. +.TP 5 +\-v [\fIprinter(s)\fR] +.br +Shows the printers and what device they are attached to. If no printers +are specified then all printers are listed. +.SH COMPATIBILITY +Unlike the System V printing system, CUPS allows printer names to contain +any printable character except SPACE and TAB. Also, printer and class names are +\fBnot\fR case-sensitive. +.LP +The "-h" option is not a standard System V option. +.SH SEE ALSO +cancel(1), lp(1), +CUPS Software User's Manual +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpstat.1 461 1999-06-24 17:44:19Z mike $". +.\" diff --git a/man/lpstat.z b/man/lpstat.z new file mode 100644 index 0000000000..76628c04ed Binary files /dev/null and b/man/lpstat.z differ diff --git a/man/mime.convs.5 b/man/mime.convs.5 new file mode 100644 index 0000000000..93e530312f --- /dev/null +++ b/man/mime.convs.5 @@ -0,0 +1,36 @@ +.\" +.\" "$Id: mime.convs.5 327 1999-05-14 17:03:06Z mike $" +.\" +.\" mime.convs man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH mime.convs 5 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +mime.convs \- mime type conversion file for cups +.SH DESCRIPTION +.SH SEE ALSO +classes.conf(5), cupsd(8), cupsd.conf(5), mime.types(5), printers.conf(5), +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: mime.convs.5 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/mime.convs.z b/man/mime.convs.z new file mode 100644 index 0000000000..27c4895c70 Binary files /dev/null and b/man/mime.convs.z differ diff --git a/man/mime.types.5 b/man/mime.types.5 new file mode 100644 index 0000000000..5381b8190f --- /dev/null +++ b/man/mime.types.5 @@ -0,0 +1,36 @@ +.\" +.\" "$Id: mime.types.5 327 1999-05-14 17:03:06Z mike $" +.\" +.\" mime.types man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH mime.types 5 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +mime.types \- mime type description file for cups +.SH DESCRIPTION +.SH SEE ALSO +classes.conf(5), cupsd(8), cupsd.conf(5), mime.convs(5), printers.conf(5), +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: mime.types.5 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/mime.types.z b/man/mime.types.z new file mode 100644 index 0000000000..60600d78a4 Binary files /dev/null and b/man/mime.types.z differ diff --git a/man/printers.conf.5 b/man/printers.conf.5 new file mode 100644 index 0000000000..490c506014 --- /dev/null +++ b/man/printers.conf.5 @@ -0,0 +1,36 @@ +.\" +.\" "$Id: printers.conf.5 327 1999-05-14 17:03:06Z mike $" +.\" +.\" printers.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-1999 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636-3111 USA +.\" +.\" Voice: (301) 373-9603 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH printers.conf 5 "Common UNIX Printing System" "14 May 1999" "Easy Software Products" +.SH NAME +printers.conf \- printer configuration file for cups +.SH DESCRIPTION +.SH SEE ALSO +classes.conf(5), cupsd(8), cupsd.conf(5), mime.convs(5), mime.types(5), +CUPS Software Administrator's Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-1999 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: printers.conf.5 327 1999-05-14 17:03:06Z mike $". +.\" diff --git a/man/printers.conf.z b/man/printers.conf.z new file mode 100644 index 0000000000..43157f31ce Binary files /dev/null and b/man/printers.conf.z differ diff --git a/ppd/Makefile b/ppd/Makefile new file mode 100644 index 0000000000..675b199e4c --- /dev/null +++ b/ppd/Makefile @@ -0,0 +1,55 @@ +# +# "$Id$" +# +# PPD file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# PPD files... +# + +FILES = deskjet.ppd laserjet.ppd + +# +# Make everything... +# + +all: + +# +# Clean all config and object files... +# + +clean: + +# +# Install files... +# + +install: + -$(MKDIR) $(DATADIR)/model + $(CP) $(FILES) $(DATADIR)/model + +# +# End of "$Id$". +# diff --git a/ppd/deskjet.ppd b/ppd/deskjet.ppd new file mode 100644 index 0000000000..cc712c3551 --- /dev/null +++ b/ppd/deskjet.ppd @@ -0,0 +1,186 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id$" +*% +*% Sample HP DeskJet driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-1999 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44145 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636-3111 USA +*% +*% Voice: (301) 373-9603 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.0" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "DESKJET.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.0)" +*cupsVersion: 1.0 +*cupsManualCopies: True +*cupsFilter: "application/vnd.cups-raster 0 rastertohp" +*ModelName: "HP DeskJet Series" +*ShortNickName: "HP DeskJet Series" +*NickName: "HP DeskJet Series CUPS v1.0" +*PSVersion: "(2017.000) 0" +*LanguageLevel: "2" +*ColorDevice: True +*DefaultColorSpace: RGB +*FileSystem: False +*Throughput: "1" +*LandscapeOrientation: Plus90 +*VariablePaperSize: False +*TTRasterizer: Type42 + +*UIConstraints: *PageSize Executive *InputSlot Envelope +*UIConstraints: *PageSize Letter *InputSlot Envelope +*UIConstraints: *PageSize Legal *InputSlot Envelope +*UIConstraints: *PageSize A4 *InputSlot Envelope +*UIConstraints: *PageSize A5 *InputSlot Envelope +*UIConstraints: *PageSize B5 *InputSlot Envelope +*UIConstraints: *Resolution 600dpi *ColorModel CMYK + +*OpenUI *PageSize/Media Size: PickOne +*OrderDependency: 10 AnySetup *PageSize +*DefaultPageSize: Letter +*PageSize Letter/Letter: "<>setpagedevice" +*PageSize Legal/Legal: "<>setpagedevice" +*PageSize Executive/Executive: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/Letter: "<>setpagedevice" +*PageRegion Legal/Legal: "<>setpagedevice" +*PageRegion Executive/Executive: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 756" +*ImageableArea Legal/US Legal: "18 36 594 972" +*ImageableArea Executive/Executive: "18 36 504 684" +*ImageableArea A4/A4: "18 36 577 806" +*ImageableArea A5/A5: "18 36 403 559" +*ImageableArea B5/JIS B5: "18 36 498 693" +*ImageableArea EnvISOB5/B5 (ISO): "18 36 463 673" +*ImageableArea Env10/Com-10: "18 36 279 648" +*ImageableArea EnvC5/EnvC5: "18 36 441 613" +*ImageableArea EnvDL/EnvDL: "18 36 294 588" +*ImageableArea EnvMonarch/Envelope Monarch: "18 36 261 504" + +*DefaultPaperDimension: Letter +*PaperDimension Letter/Letter: "612 792" +*PaperDimension Legal/Legal: "612 1008" +*PaperDimension Executive/Executive: "522 756" +*PaperDimension A4/A4: "595 842" +*PaperDimension A5/A5: "421 595" +*PaperDimension B5/B5 (JIS): "516 729" +*PaperDimension EnvISOB5/Envelope B5: "499 709" +*PaperDimension Env10/Envelope #10: "297 684" +*PaperDimension EnvC5/Envelope C5: "459 649" +*PaperDimension EnvDL/Envelope DL: "312 624" +*PaperDimension EnvMonarch/Envelope Monarch: "279 540" + +*OpenUI *MediaType/Media Type: PickOne +*OrderDependency: 10 AnySetup *MediaType +*DefaultMediaType: Plain +*MediaType Plain/Plain Paper: "<>setpagedevice" +*MediaType Bond/Bond Paper: "<>setpagedevice" +*MediaType Special/Special Paper: "<>setpagedevice" +*MediaType Transparency/Transparency: "<>setpagedevice" +*MediaType Glossy/Glossy Paper: "<>setpagedevice" +*CloseUI: *MediaType + +*OpenUI *InputSlot/Media Source: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Tray +*InputSlot Tray/Tray: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 300dpi +*Resolution 150dpi/150 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id$". +*% diff --git a/ppd/laserjet.ppd b/ppd/laserjet.ppd new file mode 100644 index 0000000000..20e0b9d78a --- /dev/null +++ b/ppd/laserjet.ppd @@ -0,0 +1,172 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id$" +*% +*% Sample HP LaserJet driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-1999 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44145 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636-3111 USA +*% +*% Voice: (301) 373-9603 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.0" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "LASERJET.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.0)" +*cupsVersion: 1.0 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-raster 0 rastertohp" +*ModelName: "HP LaserJet Series" +*ShortNickName: "HP LaserJet Series" +*NickName: "HP LaserJet Series CUPS v1.0" +*PSVersion: "(2017.000) 0" +*LanguageLevel: "2" +*ColorDevice: False +*DefaultColorSpace: Gray +*FileSystem: False +*Throughput: "8" +*LandscapeOrientation: Plus90 +*VariablePaperSize: False +*TTRasterizer: Type42 + +*UIConstraints: *PageSize Executive *InputSlot Envelope +*UIConstraints: *PageSize Letter *InputSlot Envelope +*UIConstraints: *PageSize Legal *InputSlot Envelope +*UIConstraints: *PageSize A4 *InputSlot Envelope +*UIConstraints: *PageSize A5 *InputSlot Envelope +*UIConstraints: *PageSize B5 *InputSlot Envelope + +*OpenUI *PageSize/Media Size: PickOne +*OrderDependency: 10 AnySetup *PageSize +*DefaultPageSize: Letter +*PageSize Letter/Letter: "<>setpagedevice" +*PageSize Legal/Legal: "<>setpagedevice" +*PageSize Executive/Executive: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/Letter: "<>setpagedevice" +*PageRegion Legal/Legal: "<>setpagedevice" +*PageRegion Executive/Executive: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 756" +*ImageableArea Legal/US Legal: "18 36 594 972" +*ImageableArea Executive/Executive: "18 36 504 684" +*ImageableArea A4/A4: "18 36 577 806" +*ImageableArea A5/A5: "18 36 403 559" +*ImageableArea B5/JIS B5: "18 36 498 693" +*ImageableArea EnvISOB5/B5 (ISO): "18 36 463 673" +*ImageableArea Env10/Com-10: "18 36 279 648" +*ImageableArea EnvC5/EnvC5: "18 36 441 613" +*ImageableArea EnvDL/EnvDL: "18 36 294 588" +*ImageableArea EnvMonarch/Envelope Monarch: "18 36 261 504" + +*DefaultPaperDimension: Letter +*PaperDimension Letter/Letter: "612 792" +*PaperDimension Legal/Legal: "612 1008" +*PaperDimension Executive/Executive: "522 756" +*PaperDimension A4/A4: "595 842" +*PaperDimension A5/A5: "421 595" +*PaperDimension B5/B5 (JIS): "516 729" +*PaperDimension EnvISOB5/Envelope B5: "499 709" +*PaperDimension Env10/Envelope #10: "297 684" +*PaperDimension EnvC5/Envelope C5: "459 649" +*PaperDimension EnvDL/Envelope DL: "312 624" +*PaperDimension EnvMonarch/Envelope Monarch: "279 540" + +*OpenUI *InputSlot/Media Source: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Default +*InputSlot Default/Default: "<>setpagedevice" +*InputSlot Tray1/Tray 1: "<>setpagedevice" +*InputSlot Tray2/Tray 2: "<>setpagedevice" +*InputSlot Tray3/Tray 3: "<>setpagedevice" +*InputSlot Tray4/Tray 4: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 300dpi +*Resolution 150dpi/150 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id$". +*% diff --git a/pstoraster/Fontmap b/pstoraster/Fontmap new file mode 100644 index 0000000000..42797fe18d --- /dev/null +++ b/pstoraster/Fontmap @@ -0,0 +1,98 @@ +% +% "$Id: Fontmap 569 1999-07-30 12:57:12Z mike $" +% +% Fontmap file for the Common UNIX Printing System (CUPS). +% +% Copyright 1997-1999 by Easy Software Products, all rights reserved. +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44145 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636-3111 USA +% +% Voice: (301) 373-9603 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% + +% +% The Fontmap file takes lines in the following formats: +% +% /FontName /RealFontName [for aliases] +% /FontName (FileName) [for actual font files] +% +% All Type1 fonts in the "fonts" directory (usually /usr/share/cups/fonts) +% are automagically added with the names in the font files (that is, the +% font filename doesn't matter, it looks at the file header instead). +% + +% +% The standard fonts included with ESP Print are the free GhostScript fonts, +% which don't use the standard names. These aliases map the standard 39 +% fonts to the free fonts. +% + +/Bookman-Demi /URWBookmanL-DemiBold ; +/Bookman-DemiItalic /URWBookmanL-DemiBoldItal ; +/Bookman-Light /URWBookmanL-Ligh ; +/Bookman-LightItalic /URWBookmanL-LighItal ; + +/Courier /NimbusMonL-Regu ; +/Courier-Oblique /NimbusMonL-ReguObli ; +/Courier-Bold /NimbusMonL-Bold ; +/Courier-BoldOblique /NimbusMonL-BoldObli ; + +/AvantGarde-Book /URWGothicL-Book ; +/AvantGarde-BookOblique /URWGothicL-BookObli ; +/AvantGarde-Demi /URWGothicL-Demi ; +/AvantGarde-DemiOblique /URWGothicL-DemiObli ; + +/Helvetica /NimbusSanL-Regu ; +/Helvetica-Oblique /NimbusSanL-ReguItal ; +/Helvetica-Bold /NimbusSanL-Bold ; +/Helvetica-BoldOblique /NimbusSanL-BoldItal ; + +/Helvetica-Narrow /NimbusSanL-ReguCond ; +/Helvetica-Narrow-Oblique /NimbusSanL-ReguCondItal ; +/Helvetica-Narrow-Bold /NimbusSanL-BoldCond ; +/Helvetica-Narrow-BoldOblique /NimbusSanL-BoldCondItal ; + +/Palatino-Roman /URWPalladioL-Roma ; +/Palatino-Italic /URWPalladioL-Ital ; +/Palatino-Bold /URWPalladioL-Bold ; +/Palatino-BoldItalic /URWPalladioL-BoldItal ; + +/NewCenturySchlbk-Roman /CenturySchL-Roma ; +/NewCenturySchlbk-Italic /CenturySchL-Ital ; +/NewCenturySchlbk-Bold /CenturySchL-Bold ; +/NewCenturySchlbk-BoldItalic /CenturySchL-BoldItal ; + +/Times-Roman /NimbusRomNo9L-Regu ; +/Times-Italic /NimbusRomNo9L-ReguItal ; +/Times-Bold /NimbusRomNo9L-Medi ; +/Times-BoldItalic /NimbusRomNo9L-MediItal ; + +/Symbol /StandardSymL ; + +/ZapfChancery-MediumItalic /URWChanceryL-MediItal ; + +/ZapfDingbats /Dingbats ; + +% +% This alias is for less-intelligent PC programs like Quark and +% Freehand which insist on using "Times" as the name for the +% "Times-Roman" font. Go figure. +% + +/Times /Times-Roman ; + +% +% End of "$Id: Fontmap 569 1999-07-30 12:57:12Z mike $". +% diff --git a/pstoraster/Makefile b/pstoraster/Makefile new file mode 100644 index 0000000000..518d0121b1 --- /dev/null +++ b/pstoraster/Makefile @@ -0,0 +1,167 @@ +# +# "$Id$" +# +# GNU Ghostscript makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-1999 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636-3111 USA +# +# Voice: (301) 373-9603 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# +# This makefile and any derivative of it may be used and distributed +# freely under the terms of the GNU General Public License when +# used with GNU Ghostscript or its derivatives. Use of the makefile +# (or any derivative of it) with software other than GNU GhostScript +# (or its derivatives) is governed by the CUPS license agreement. +# + +include ../Makedefs + +# +# Object files... +# + +LIBOBJS = gconf.o gdevabuf.o gdevcups.o gdevddrw.o gdevdflt.o \ + gdevemap.o gdevm1.o gdevm16.o gdevm2.o gdevm24.o \ + gdevm32.o gdevm4.o gdevm8.o gdevmem.o gdevmpla.o \ + gdevmrop.o gdevnfwd.o gdevpipe.o gdevprn.o gp_nofb.o \ + gp_unifn.o gp_unifs.o gp_unix.o gsalloc.o gsbitops.o \ + gsbittab.o gscdef.o gschar.o gschar0.o gscie.o \ + gscolor.o gscolor1.o gscolor2.o gscoord.o gscsepr.o \ + gsdevice.o gsdevmem.o gsdparam.o gsdps1.o gsfont.o \ + gsfont0.o gshsb.o gsht.o gsht1.o gshtscr.o gsimage.o \ + gsimpath.o gsinit.o gsiodev.o gsline.o gsmatrix.o \ + gsmemory.o gsmisc.o gspaint.o gsparam.o gspath.o \ + gspath1.o gspcolor.o gsrop.o gsroptab.o gsstate.o \ + gstype1.o gstype42.o gsutil.o gxacpath.o gxbcache.o \ + gxccache.o gxccman.o gxcht.o gxclbits.o gxclfile.o \ + gxclimag.o gxclip2.o gxclist.o gxclpath.o gxclread.o \ + gxcmap.o gxcpath.o gxctable.o gxdcconv.o gxdcolor.o \ + gxdither.o gxfill.o gxhint1.o gxhint2.o gxhint3.o \ + gxht.o gximage.o gximage0.o gximage1.o gximage2.o \ + gximage3.o gximage4.o gximage5.o gxpaint.o gxpath.o \ + gxpath2.o gxpcmap.o gxpcopy.o gxpdash.o gxstroke.o \ + ialloc.o ibnum.o iccinit0.o iconf.o idebug.o idict.o \ + idparam.o igc.o igcref.o igcstr.o iinit.o ilocate.o \ + imain.o iname.o interp.o iparam.o ireclaim.o isave.o \ + iscan.o iscanbin.o iscannum.o iscantab.o istack.o \ + iutil.o iutil2.o sbcp.o sbhc.o sbwbs.o \ + scfd.o scfdtab.o scfe.o scfetab.o sdctc.o sdctd.o \ + sdcte.o seexec.o sfile.o sfilter1.o sfilter2.o shc.o \ + shcgen.o siscale.o sjpegc.o sjpegd.o sjpege.o \ + sjpegerr.o slzwc.o slzwce.o slzwd.o smtf.o spcxd.o \ + spdiff.o spngp.o srld.o srle.o sstring.o stream.o \ + szlibc.o szlibd.o szlibe.o zarith.o zarray.o zbseq.o \ + zchar.o zchar1.o zchar2.o zchar42.o zcharout.o zcie.o \ + zcolor.o zcolor1.o zcolor2.o zcontrol.o zcrd.o \ + zcsindex.o zcssepr.o zdevcal.o zdevice.o zdevice2.o \ + zdict.o zdps1.o zfbcp.o zfdctc.o zfdctd.o zfdcte.o \ + zfdecode.o zfile.o zfileio.o zfilter.o zfilter2.o \ + zfilterx.o zfname.o zfont.o zfont0.o zfont1.o zfont2.o \ + zfont42.o zfproc.o zfzlib.o zgeneric.o zgstate.o zhsb.o \ + zht.o zht1.o zht2.o zimage2.o ziodev.o ziodev2.o \ + zmath.o zmatrix.o zmedia2.o zmisc.o zmisc1.o zmisc2.o \ + zpacked.o zpaint.o zpath.o zpath1.o zpcolor.o zrelbit.o \ + zstack.o zstring.o zsysvm.o ztoken.o ztype.o zupath.o \ + zusparam.o zvmem.o zvmem2.o +OBJS = $(LIBOBJS) genarch.o pstoraster.o + +# +# Data files... +# + +DFILES = Fontmap gs_btokn.ps gs_ccfnt.ps gs_cidfn.ps gs_cmap.ps \ + gs_cmdl.ps gs_dbt_e.ps gs_diskf.ps gs_dps1.ps \ + gs_fform.ps gs_fonts.ps gs_init.ps gs_iso_e.ps \ + gs_kanji.ps gs_ksb_e.ps gs_l2img.ps gs_lev2.ps \ + gs_mex_e.ps gs_mro_e.ps gs_pdfwr.ps gs_pdf.ps \ + gs_pdf_e.ps gs_pfile.ps gs_res.ps gs_setpd.ps \ + gs_statd.ps gs_std_e.ps gs_sym_e.ps gs_ttf.ps \ + gs_typ42.ps gs_type1.ps gs_wan_e.ps gs_wl1_e.ps \ + gs_wl2_e.ps gs_wl5_e.ps pdf_2ps.ps pdf_base.ps \ + pdf_draw.ps pdf_font.ps pdf_main.ps pdf_sec.ps \ + pfbtogs.ps + +# +# Targets... +# + +TARGETS = genarch arch.h libgs.a pstoraster + +# +# Make everything... +# + +all: $(TARGETS) + +# +# Clean all config and object files... +# + +clean: + $(RM) $(TARGETS) + $(RM) $(OBJS) + +# +# Install files... +# + +install: $(TARGETS) + -$(MKDIR) $(SERVERROOT)/filter + $(CP) pstoraster $(SERVERROOT)/filter + -$(LN) pstoraster $(SERVERROOT)/filter/pdftops + -$(MKDIR) $(DATADIR)/pstoraster + $(CP) $(DFILES) $(DATADIR)/pstoraster + +# +# genarch - generate the architecture configuration file. +# + +genarch: genarch.o + echo Linking $@... + $(CC) $(LDFLAGS) -o genarch genarch.o +arch.h: genarch + echo Generating $@... + ./genarch arch.h + +# +# libgs.a - GhostScript interpreter library... +# + +libgs.a: $(LIBOBJS) ../Makedefs + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + +gdevcups.o: ../cups/raster.h +gconf.o iconf.o gscdef.o: gconfig.h +$(LIBOBJS): arch.h ../config.h ../Makedefs + + +# +# pstoraster - PostScript RIP filter. +# + +pstoraster: pstoraster.o libgs.a ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o pstoraster pstoraster.o libgs.a \ + $(LIBJPEG) $(LIBZ) $(LIBS) -lm +pstoraster.o: arch.h ../config.h ../Makedefs + +# +# End of "$Id$". +# diff --git a/pstoraster/bfont.h b/pstoraster/bfont.h new file mode 100644 index 0000000000..a653ce3998 --- /dev/null +++ b/pstoraster/bfont.h @@ -0,0 +1,54 @@ +/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* bfont.h */ +/* Interpreter internal routines and data needed for building fonts */ +/* Requires gxfont.h */ +#include "ifont.h" + +/* In zfont.c */ +int add_FID(P2(ref *pfdict, gs_font *pfont)); +font_proc_make_font(zdefault_make_font); +font_proc_make_font(zbase_make_font); +/* The global font directory */ +extern gs_font_dir *ifont_dir; + +/* Structure for passing BuildChar and BuildGlyph procedures. */ +typedef struct build_proc_refs_s { + ref BuildChar; + ref BuildGlyph; +} build_proc_refs; + +/* In zfont2.c */ +int build_proc_name_refs(P3(build_proc_refs *pbuild, + const char _ds *bcstr, + const char _ds *bgstr)); +int build_gs_font_procs(P2(os_ptr, build_proc_refs *)); +int build_gs_primitive_font(P5(os_ptr, gs_font_base **, font_type, + gs_memory_type_ptr_t, const build_proc_refs *)); +int build_gs_simple_font(P5(os_ptr, gs_font_base **, font_type, + gs_memory_type_ptr_t, const build_proc_refs *)); +void lookup_gs_simple_font_encoding(P1(gs_font_base *)); +int build_gs_font(P5(os_ptr, gs_font **, font_type, + gs_memory_type_ptr_t, const build_proc_refs *)); +int define_gs_font(P1(gs_font *)); diff --git a/pstoraster/bseq.h b/pstoraster/bseq.h new file mode 100644 index 0000000000..46dab4a60f --- /dev/null +++ b/pstoraster/bseq.h @@ -0,0 +1,66 @@ +/* Copyright (C) 1990, 1994 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* bseq.h */ +/* Definitions for Level 2 binary object sequences */ + +/* Binary object sequence element types */ +typedef enum { + bs_null = 0, + bs_integer = 1, + bs_real = 2, + bs_name = 3, + bs_boolean = 4, + bs_string = 5, + bs_eval_name = 6, + bs_array = 9, + bs_mark = 10, + /* + * We extend the PostScript language definition by allowing + * dictionaries in binary object sequences. The data for + * a dictionary is like that for an array, with the following + * changes: + * - If the size is an even number, the value is the index of + * the first of a series of alternating keys and values. + * - If the size is 1, the value is the index of another + * object (which must also be a dictionary, and must not have + * size = 1); this object represents the same object as that one. + */ + bs_dictionary = 15 +} bin_seq_type; +#define bs_executable 128 + +/* Definition of an object in a binary object sequence. */ +typedef struct { + byte tx; /* type and executable flag */ + byte unused; + union { + bits16 w; + byte b[2]; + } size; + union { + bits32 w; + float f; + byte b[4]; + } value; +} bin_seq_obj; diff --git a/pstoraster/btoken.h b/pstoraster/btoken.h new file mode 100644 index 0000000000..69a7d63e91 --- /dev/null +++ b/pstoraster/btoken.h @@ -0,0 +1,65 @@ +/* Copyright (C) 1990 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* btoken.h */ +/* Definitions for Level 2 binary tokens */ + +/* Binary token types */ +typedef enum { + bt_seq = 128, + bt_seq_IEEE_msb = 128, /* binary object sequence, */ + /* IEEE floats, big-endian */ + bt_seq_IEEE_lsb = 129, /* ditto, little-endian */ + bt_seq_native_msb = 130, /* ditto, native floats, big-endian */ + bt_seq_native_lsb = 131, /* ditto, little-endian */ + bt_int32_msb = 132, + bt_int32_lsb = 133, + bt_int16_msb = 134, + bt_int16_lsb = 135, + bt_int8 = 136, + bt_fixed = 137, + bt_float_IEEE_msb = 138, + bt_float_IEEE_lsb = 139, + bt_float_native = 140, + bt_boolean = 141, + bt_string_256 = 142, + bt_string_64k_msb = 143, + bt_string_64k_lsb = 144, + bt_litname_system = 145, + bt_execname_system = 146, + bt_litname_user = 147, + bt_execname_user = 148, + bt_num_array = 149 +} bt_char; +#define bt_char_min 128 +#define bt_char_max 159 + +/* Define the number of required initial bytes for binary tokens */ +/* (including the token type byte). */ +extern const byte bin_token_bytes[]; /* in iscan2.c */ +#define bin_token_bytes_values\ + 4, 4, 4, 4, 5, 5, 3, 3, 2, 2, 5, 5, 5,\ + 2, 2, 3, 3, 2, 2, 2, 2, 4,\ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /* undefined */ +#define binary_token_bytes(btchar)\ + (bin_token_bytes[(btchar) - bt_char_min]) diff --git a/pstoraster/ctype_.h b/pstoraster/ctype_.h new file mode 100644 index 0000000000..42af5c4a38 --- /dev/null +++ b/pstoraster/ctype_.h @@ -0,0 +1,31 @@ +/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* ctype_.h */ +/* Wrapper for ctype.h */ + +/* We must include std.h before any file that includes sys/types.h. */ +#include "std.h" + +/* ... and that's the only reason for having this file at all. */ +#include diff --git a/pstoraster/dirent_.h b/pstoraster/dirent_.h new file mode 100644 index 0000000000..548de3bab9 --- /dev/null +++ b/pstoraster/dirent_.h @@ -0,0 +1,50 @@ +/* + Copyright 1993-1999 by Easy Software Products. + Copyright (C) 1993 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* dirent_.h */ +/* Generic substitute for Unix dirent.h */ + +/* We must include std.h before any file that includes sys/types.h. */ +#include "std.h" + +#include + +/* Directory entries may be defined in quite a number of different */ +/* header files. The following switches are defined in gconfig_.h. */ +#ifdef HAVE_DIRENT_H +# include +typedef struct dirent dir_entry; +#else +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +typedef struct direct dir_entry; +#endif diff --git a/pstoraster/dstack.h b/pstoraster/dstack.h new file mode 100644 index 0000000000..b897393c5a --- /dev/null +++ b/pstoraster/dstack.h @@ -0,0 +1,307 @@ +/* Copyright (C) 1992, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* dstack.h */ +/* Definitions for the dictionary stack */ +#include "istack.h" + +/* Define the dictionary stack and systemdict. */ +extern ref_stack d_stack; +extern ref ref_systemdict; +#define systemdict (&ref_systemdict) + +/* Define the dictionary stack pointers. */ +typedef s_ptr ds_ptr; +typedef const_s_ptr const_ds_ptr; +#define dsbot (d_stack.bot) +#define dsp (d_stack.p) +#define dstop (d_stack.top) + +/* Macro to ensure enough room on the dictionary stack */ +#define check_dstack(n)\ + if ( dstop - dsp < (n) )\ + { d_stack.requested = (n); return_error(e_dictstackoverflow); } + +/* Check whether a dictionary is one of the permanent ones on the d-stack. */ +bool dict_is_permanent_on_dstack(P1(const ref *)); + +/* + * Switching between Level 1 and Level 2 involves inserting and removing + * globaldict on the dictionary stack. Instead of truly inserting and + * removing entries, we replace globaldict by a copy of systemdict in + * Level 1 mode. min_dstack_size, the minimum number of entries, does not + * change depending on language level; the countdictstack and dictstack + * operators must take this into account. + */ +extern uint min_dstack_size; + +/* + * The dictionary stack is implemented as a linked list of blocks; + * operators that access the entire d-stack must take this into account. + * These are: + * countdictstack dictstack + * In addition, name lookup requires searching the entire stack, not just + * the top block, and the underflow check for the dictionary stack + * (`end' operator) is not just a check for underflowing the top block. + */ + +/* + * Cache a value for fast checking of def operations. + * If the top entry on the dictionary stack is a writable dictionary, + * dsspace is the space of the dictionary; if it is a non-writable + * dictionary, dsspace = -1. Then def is legal precisely if + * r_space(pvalue) <= dsspace. Note that in order for this trick to work, + * the result of r_space must be a signed integer; some compilers treat + * enums as unsigned, probably in violation of the ANSI standard. + */ +extern int dsspace; +#define dtop_can_store(pvalue) ((int)r_space(pvalue) <= dsspace) +/* + * Cache values for fast name lookup. If the top entry on the dictionary + * stack is a readable dictionary with packed keys, dtop_keys, dtop_npairs, + * and dtop_values are keys.value.packed, npairs, and values.value.refs + * for that dictionary; otherwise, these variables point to a dummy + * empty dictionary. + */ +extern const ref_packed *dtop_keys; +extern uint dtop_npairs; +extern ref *dtop_values; +/* + * Reset the cached top values. Every routine that alters the + * dictionary stack (including changing the protection or size of the + * top dictionary on the stack) must call this. + */ +void dict_set_top(P0()); + +/* + * Define a special fast entry for name lookup in the interpreter. + * The key is known to be a name; search the entire dict stack. + * Return the pointer to the value slot. + * If the name isn't found, just return 0. + */ +ref *dict_find_name_by_index(P1(uint nidx)); +#define dict_find_name(pnref) dict_find_name_by_index(name_index(pnref)) + +/* Define some auxiliary macros needed for inline code. */ + +#define hash_mod_large(hash, size) ((hash) & ((size) - 1)) +#define hash_mod_small(hash, size) ((hash) % (size)) +#define dict_round_size_large(asize)\ + while ( asize & (asize - 1) ) asize = (asize | (asize - 1)) + 1 +#define dict_round_size_small(asize)\ + DO_NOTHING +#if arch_small_memory +# define hash_mod(h, s) hash_mod_small(h, s) +# define dict_round_size(s) dict_round_size_small(s) +#else +# ifdef DEBUG +# define hash_mod(h, s)\ + (gs_debug_c('.') ? hash_mod_small(h, s) : hash_mod_large(h, s)) +# define dict_round_size(s)\ + if ( !gs_debug_c('.') ) dict_round_size_large(s) +# else +# define hash_mod(h, s) hash_mod_large(h, s) +# define dict_round_size(s) dict_round_size_large(s) +# endif +#endif + +/* Define the hashing function for names. */ +/* We don't have to scramble the index, because */ +/* indices are assigned in a scattered order (see name_ref in iname.c). */ +#define dict_name_index_hash(nidx) (nidx) + +/* + * Define an extra-fast macro for name lookup, optimized for + * a single-probe lookup in the top dictionary on the stack. + * Amazingly enough, this seems to hit over 90% of the time + * (aside from operators, of course, which are handled either with + * the special cache pointer or with 'bind'). + */ +#define dict_find_name_by_index_inline(nidx,htemp)\ + (dtop_keys[htemp = hash_mod(dict_name_index_hash(nidx),\ + dtop_npairs) + 1] == pt_tag(pt_literal_name) + (nidx) ?\ + dtop_values + htemp : dict_find_name_by_index(nidx)) +/* + * Define a similar macro that only checks the top dictionary on the stack. + */ +#define if_dict_find_name_by_index_top(nidx,htemp,pvslot)\ + if ( ((dtop_keys[htemp = hash_mod(dict_name_index_hash(nidx),\ + dtop_npairs) + 1] == pt_tag(pt_literal_name) + (nidx)) ?\ + ((pvslot) = dtop_values + (htemp), 1) :\ + 0)\ + ) + +/* +Notes on dictionary lookup performance +-------------------------------------- + +We mark heavily used operations with a * below; moderately heavily used +operations with a +. + +The following operations change the dictionary stack: + +begin, +end + readonly (on a dictionary that is on the stack) + noaccess (on a dictionary that is on the stack) +We implement cleardictstack as a series of ends. + +The following operations change the contents of dictionaries: + *def, +put + undef + restore + .setmaxlength +We implement store in PostScript, and copy as a series of puts. Many +other operators also do puts (e.g., ScaleMatrix in makefont, +Implementation in makepattern, ...). Note that put can do an implicit +.setmaxlength (if it has to grow the dictionary). + +The following operations look up keys on the dictionary stack: + *(interpreter name lookup) + load + where + +Current design +-------------- + +Each name has a pointer that has one of 3 states: + - This name has no definitions. + - This name has exactly one definition, in systemdict or userdict. + In this case, the pointer points to the value slot. + - This name has some other status. + +We cache some pointers to the top dictionary on the stack if it is a +readable dictionary with packed keys, which allows us to do fast, +single-probe lookups in this dictionary. We also cache a value that +allows us to do a fast check for stores into the top dictionary +(writability + space check). + +Full shallow binding +-------------------- + +We implement shallow binding with a pointer in each name that points to +the value slot that holds the name's definition. If the name is +undefined, or if we don't know where the slot is, the binding pointer +points to a ref with a special type t__invalid, which cannot occur +anywhere else. "Clearing" the pointer means setting it to point to this +ref. + +We also maintain a pair of pointers that bracket the value region of the +top dictionary on the stack, for fast checking in def. If the top +dictionary is readonly or noaccess, the pointers designate an empty area. +We call this the "def region" cache. + +We implement the above operations as follows: + begin - push the dictionary on the stack; set the pointers of + all name keys to point to the corresponding value slots. + end - pop the stack; clear the pointers of all name keys. + readonly - if the dictionary is the top one on the stack, + reset the def region cache. + noaccess - clear the pointers of all name keys. (This is overly + conservative, but this is a very rare operation.) + Also reset the def region cache if the dictionary is + the top one on the stack. + def - if the key is a name and its pointer points within the cached + def region, store the value through the pointer; otherwise, + look up the key in the top dictionary, store the value, + and if the key is a name, set its pointer to the value slot. + put - if the key is a name and wasn't in the dictionary before, + clear its pointer. (Conservative, but rare.) + undef - if the key is a name, clear its pointer. (Overly + conservative, but rare.) + restore - if either the old or the new value of a change is a name + (possibly in a packed array), clear its pointer. This is + conservative, but easy to detect, and probably not *too* + conservative. + .setmaxlength - clear all the pointers, like noaccess. + (name lookup) - fetch the value through the pointer and dispatch + on its type; if the type is t__invalid, do a full search + and set the pointer. This avoids a separate check for a + clear pointer in the usual case where the pointer is valid. + load - if the pointer is clear, do a search and set the pointer; + then fetch the value. + where - always do a full search and set the pointer. + (Conservative, but rare.) + +One place where shallow binding will result in major new overhead is the +extra push of systemdict for loading fonts. This probably isn't a problem +in real life. + +Adaptive shallow binding +------------------------ + +We do validity checking for the name value cache using an epoch counter. +For each dictionary D, we keep an on-stack flag F. Each dictionary stack +entry is where D is the actual dictionary, M is a mark vector of +V bits (V is a system constant, probably 64), F is D's former on-stack +flag, and E is the epoch at which the entry was made. For each name K, we +keep a cache where P is a pointer to the dictionary value slot that +holds the current value of K, and E is an epoch value; the cache is valid +if K->E >= dsp->E. Here is what happens for each operation: + +****** Still need to handle names defined only in systemdict or userdict? + +To initialize: + Epoch = 0 +To clear the cache entry for K: + *K = +begin(D): + *++dsp = F, ++Epoch> + set D->F +value = lookup(K): + if K->E >= dsp->E + value = *K->P + else + do lookup as usual + *K = + set dp->M[i mod V] where dp is the dstack slot of the dictionary + where K was found and i is the index within that dictionary +end: + for each i such that dsp->M[i] is set, + clear the cache entry for dsp->D->keys[i, i+V, ...] + dsp->D->F = dsp->F + --dsp +noaccess(D): + if D->F is set, + clear the cache entries for all name keys of D +readonly(D): + << nothing >> +.setmaxlength(D,N): + same as noaccess +restore: + If either the old or the new value of a change is a name + (possibly in a packed array), clear its cache entry. This is + conservative, but easy to detect, and probably not *too* + conservative. +def(K,V): + if K->P points into dsp->D + *K->P = V + else + put the new value in dsp->D + set *K and dsp->M[i mod V] as for a lookup +put(D,K,V): + if K is already defined in D, do nothing special + otherwise, if D->F isn't set, do nothing special + otherwise, clear K's cache entry +undef(D,K): + if D->F is set, + clear K's cache entry +*/ diff --git a/pstoraster/errno_.h b/pstoraster/errno_.h new file mode 100644 index 0000000000..f5dbfdebe5 --- /dev/null +++ b/pstoraster/errno_.h @@ -0,0 +1,35 @@ +/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* errno_.h */ +/* Generic substitute for Unix errno.h */ + +/* We must include std.h before any file that includes sys/types.h. */ +#include "std.h" + +/* All environments provide errno.h, but in some of them, errno.h */ +/* only defines the error numbers, and doesn't declare errno. */ +#include +#ifndef errno /* in case it was #defined (very implausible!) */ +extern int errno; +#endif diff --git a/pstoraster/errors.h b/pstoraster/errors.h new file mode 100644 index 0000000000..9c9defcce0 --- /dev/null +++ b/pstoraster/errors.h @@ -0,0 +1,179 @@ +/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* errors.h */ +/* Definition of error codes */ + +/* + * A procedure that may return an error always returns + * a non-negative value (zero, unless otherwise noted) for success, + * or negative for failure. + * We use ints rather than an enum to avoid a lot of casting. + */ + +/* + * The following peculiar structure allows us to include this file + * wherever error code definitions are needed, and use the same file + * to generate the table of error names by setting INCLUDE_ERROR_NAMES. + */ + +# ifdef INCLUDE_ERROR_NAMES + +/* Define the error name table */ +const char _ds *gs_error_names[] = { +#define _e_(code,name) name, + +# else /* !INCLUDE_ERROR_NAMES */ + +extern const char _ds *gs_error_names[]; +# define _e_(code,name) + +#endif /* (!)INCLUDE_ERROR_NAMES */ + + /* ------ PostScript Level 1 errors ------ */ + +#define e_unknownerror (-1) /* unknown error */ + _e_(e_unknown, "unknownerror") +#define e_dictfull (-2) + _e_(e_dictfull, "dictfull") +#define e_dictstackoverflow (-3) + _e_(e_dictstackoverflow, "dictstackoverflow") +#define e_dictstackunderflow (-4) + _e_(e_dictstackunderflow, "dictstackunderflow") +#define e_execstackoverflow (-5) + _e_(e_execstackoverflow, "execstackoverflow") +#define e_interrupt (-6) +/* We also need to define gs_error_interrupt, for gpcheck.h. */ +#undef gs_error_interrupt +#define gs_error_interrupt e_interrupt + _e_(e_interrupt, "interrupt") +#define e_invalidaccess (-7) + _e_(e_invalidaccess, "invalidaccess") +#define e_invalidexit (-8) + _e_(e_invalidexit, "invalidexit") +#define e_invalidfileaccess (-9) + _e_(e_invalidfileaccess, "invalidfileaccess") +#define e_invalidfont (-10) + _e_(e_invalidfont, "invalidfont") +#define e_invalidrestore (-11) + _e_(e_invalidrestore, "invalidrestore") +#define e_ioerror (-12) + _e_(e_ioerror, "ioerror") +#define e_limitcheck (-13) + _e_(e_limitcheck, "limitcheck") +#define e_nocurrentpoint (-14) + _e_(e_nocurrentpoint, "nocurrentpoint") +#define e_rangecheck (-15) + _e_(e_rangecheck, "rangecheck") +#define e_stackoverflow (-16) + _e_(e_stackoverflow, "stackoverflow") +#define e_stackunderflow (-17) + _e_(e_stackunderflow, "stackunderflow") +#define e_syntaxerror (-18) + _e_(e_syntaxerror, "syntaxerror") +#define e_timeout (-19) + _e_(e_timeout, "timeout") +#define e_typecheck (-20) + _e_(e_typecheck, "typecheck") +#define e_undefined (-21) + _e_(e_undefined, "undefined") +#define e_undefinedfilename (-22) + _e_(e_undefinedfilename, "undefinedfilename") +#define e_undefinedresult (-23) + _e_(e_undefinedresult, "undefinedresult") +#define e_unmatchedmark (-24) + _e_(e_unmatchedmark, "unmatchedmark") +#define e_VMerror (-25) + _e_(e_VMerror, "VMerror") + + /* ------ Additional Level 2 and DPS errors ------ */ + +#define e_configurationerror (-26) + _e_(e_configurationerror, "configurationerror") +#define e_invalidcontext (-27) + _e_(e_invalidcontext, "invalidcontext") +#define e_undefinedresource (-28) + _e_(e_undefinedresource, "undefinedresource") +#define e_unregistered (-29) + _e_(e_unregistered, "unregistered") + +# ifdef INCLUDE_ERROR_NAMES + +/* End of error name table */ + 0 +}; + +# endif /* INCLUDE_ERROR_NAMES */ + + /* ------ Pseudo-errors used internally ------ */ + +/* + * Internal code for a fatal error. + * gs_interpret also returns this for a .quit with a positive exit code. + */ +#define e_Fatal (-100) + +/* + * Internal code for the .quit operator. + * The real quit code is an integer on the operand stack. + * gs_interpret returns this only for a .quit with a zero exit code. + */ +#define e_Quit (-101) + +/* + * Internal code for a normal exit from the interpreter. + * Do not use outside of interp.c. + */ +#define e_InterpreterExit (-102) + +/* + * Internal code that indicates that a procedure has been inserted + * on the e-stack at (former) esp+2, to be executed before retrying + * the current token. This is used for color remapping + * involving a call back into the interpreter -- inelegant, but effective. + */ +#define e_InsertProc (-103) + +/* + * Internal code to indicate we have underflowed the top block + * of the e-stack. + */ +#define e_ExecStackUnderflow (-104) + +/* + * Internal code for the vmreclaim operator with a positive operand. + * We need to handle this as an error because otherwise the interpreter + * won't reload enough of its state when the operator returns. + */ +#define e_VMreclaim (-105) + +/* + * Internal code for requesting more input from run_string. + */ +#define e_NeedInput (-106) + +/* + * Define which error codes require re-executing the current object. + */ +#define error_is_interrupt(ecode)\ + ((ecode) == e_interrupt || (ecode) == e_timeout) diff --git a/pstoraster/estack.h b/pstoraster/estack.h new file mode 100644 index 0000000000..3dfd42b75c --- /dev/null +++ b/pstoraster/estack.h @@ -0,0 +1,137 @@ +/* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* estack.h */ +/* Definitions for the execution stack */ +#include "istack.h" + +/* Define the execution stack pointers. */ +typedef s_ptr es_ptr; +typedef const_s_ptr const_es_ptr; +extern ref_stack e_stack; +#define esbot (e_stack.bot) +#define esp (e_stack.p) +#define estop (e_stack.top) + +/* + * To improve performance, we cache the currentfile pointer + * (i.e., `shallow-bind' it in Lisp terminology). The invariant is as + * follows: either esfile points to the currentfile slot on the estack + * (i.e., the topmost slot with an executable file), or it is 0. + * To maintain the invariant, it is sufficient that whenever a routine + * pushes or pops anything on the estack, if the object *might* be + * an executable file, invoke esfile_clear_cache(); alternatively, + * immediately after pushing an object, invoke esfile_check_cache(). + */ +extern ref *esfile; +#define esfile_clear_cache() (esfile = 0) +#define esfile_set_cache(pref) (esfile = (pref)) +#define esfile_check_cache()\ + if ( r_has_type_attrs(esp, t_file, a_executable) )\ + esfile_set_cache(esp) + +/* + * The execution stack is used for three purposes: + * + * - Procedures being executed are held here. They always have + * type = t_array, t_mixedarray, or t_shortarray, with a_executable set. + * More specifically, the e-stack holds the as yet unexecuted tail of the + * procedure. + * + * - if, ifelse, etc. push arguments to be executed here. + * They may be any kind of object whatever. + * + * - Control operators (filenameforall, for, repeat, loop, forall, + * pathforall, run, stopped, ...) mark the stack by pushing + * an object with type = t_null, attrs = a_executable, size = es_xxx + * (see below), and value.opproc = a cleanup procedure that will get called + * whenever the execution stack is about to get cut back beyond this point + * (either for normal completion of the operator, or any kind of exit). + * (Executable null objects can't ever appear on the e-stack otherwise: + * if a control operator pushes one, it gets popped immediately.) + * The cleanup procedure is called with esp pointing just BELOW the mark, + * i.e., the mark has already been popped. + * + * The loop operators also push whatever state they need, + * followed by an operator object that handles continuing the loop. + * + * Note that there are many internal looping operators -- for example, + * all the 'show' operators can behave like loops, since they may call out + * to BuildChar procedures. + */ + +/* Macro for marking the execution stack */ +#define make_mark_estack(ep, es_idx, proc)\ + make_tasv(ep, t_null, a_executable, es_idx, opproc, proc) +#define push_mark_estack(es_idx, proc)\ + (++esp, make_mark_estack(esp, es_idx, proc)) +#define r_is_estack_mark(ep)\ + r_has_type_attrs(ep, t_null, a_executable) +#define estack_mark_index(ep) r_size(ep) + +/* Macro for pushing an operator on the execution stack */ +/* to represent a continuation procedure */ +#define make_op_estack(ep, proc)\ + make_oper(ep, 0, proc) +#define push_op_estack(proc)\ + (++esp, make_op_estack(esp, proc)) + +/* Macro to ensure enough room on the execution stack */ +#define check_estack(n)\ + if ( esp > estop - (n) )\ + { int es_code_ = ref_stack_extend(&e_stack, n);\ + if ( es_code_ < 0 ) return es_code_;\ + } + +/* Macro to ensure enough entries on the execution stack */ +#define check_esp(n)\ + if ( esp < esbot + ((n) - 1) )\ + { e_stack.requested = (n); return_error(e_ExecStackUnderflow); } + +/* Define the various kinds of execution stack marks. */ +#define es_other 0 /* internal use */ +#define es_show 1 /* show operators */ +#define es_for 2 /* iteration operators */ +#define es_stopped 3 /* stopped operator */ + +/* Pop a given number of elements off the execution stack, */ +/* executing cleanup procedures as necessary. */ +void pop_estack(P1(uint)); + +/* + * The execution stack is implemented as a linked list of blocks; + * operators that can push or pop an unbounded number of values, or that + * access the entire o-stack, must take this into account. These are: + * exit .stop .instopped countexecstack execstack currentfile + * pop_estack(exit, stop, error recovery) + * gs_show_find(all the show operators) + * In addition, for e-stack entries created by control operators, we must + * ensure that the mark and its data are never separated. We do this + * by ensuring that when splitting the top block, at least N items + * are kept in the new top block above the bottommost retained mark, + * where N is the largest number of data items associated with a mark. + * Finally, in order to avoid specific checks for underflowing a block, + * we put a guard entry at the bottom of each block except the top one + * that contains a procedure that returns an internal "exec stack block + * underflow" error. + */ diff --git a/pstoraster/files.h b/pstoraster/files.h new file mode 100644 index 0000000000..f7c320997b --- /dev/null +++ b/pstoraster/files.h @@ -0,0 +1,142 @@ +/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* files.h */ +/* Common declarations for zfile.c and zfileio.c */ +/* Requires stream.h */ + +/* + * In many places below, a do {...} while (0) avoids problems with a possible + * enclosing 'if'. + */ + +/* + * File objects store a pointer to a stream in value.pfile. + * A file object is valid if its "size" matches the read_id or write_id + * (as appropriate) in the stream it points to. This arrangement + * allows us to detect closed files reliably, while allowing us to + * reuse closed streams for new files. + */ +#define fptr(pref) (pref)->value.pfile +#define make_file(pref,a,id,s)\ + make_tasv(pref,t_file,a,id,pfile,s) + +/* The stdxxx files. We have to access them through procedures, */ +/* because they might have to be opened when referenced. */ +int zget_stdin(P1(stream **)); +int zget_stdout(P1(stream **)); +int zget_stderr(P1(stream **)); +extern bool gs_stdin_is_interactive; +/* An invalid (closed) file. */ +extern stream *invalid_file_entry; + +/* Macros for checking file validity. */ +#define file_is_valid(svar,op)\ + (svar = fptr(op), (svar->read_id | svar->write_id) == r_size(op)) +#define check_file(svar,op)\ + do\ + { check_type(*(op), t_file);\ + if ( !file_is_valid(svar, op) ) return_error(e_invalidaccess);\ + }\ + while (0) + +/* + * If a file is open for both reading and writing, its read_id, write_id, + * and stream procedures and modes reflect the current mode of use; + * an id check failure will switch it to the other mode. + */ +int file_switch_to_read(P1(const ref *)); +#define check_read_file(svar,op)\ + do\ + { check_read_type(*(op), t_file);\ + check_read_known_file(svar, op, return);\ + }\ + while (0) +#define check_read_known_file(svar,op,error_return)\ + check_read_known_file_else(svar, op, error_return, svar = invalid_file_entry) +/* The do... avoids problems with a possible enclosed 'if'. */ +#define check_read_known_file_else(svar,op,error_return,invalid_action)\ + do\ + { svar = fptr(op);\ + if ( svar->read_id != r_size(op) )\ + { if ( svar->read_id == 0 && svar->write_id == r_size(op) )\ + { int fcode = file_switch_to_read(op);\ + if ( fcode < 0 ) error_return(fcode);\ + }\ + else do { invalid_action; } while (0); /* closed or reopened file */\ + }\ + }\ + while (0) +int file_switch_to_write(P1(const ref *)); +#define check_write_file(svar,op)\ + do\ + { check_write_type(*(op), t_file);\ + check_write_known_file(svar, op, return);\ + }\ + while (0) +#define check_write_known_file(svar,op,error_return)\ + do\ + { svar = fptr(op);\ + if ( svar->write_id != r_size(op) )\ + { int fcode = file_switch_to_write(op);\ + if ( fcode < 0 ) error_return(fcode);\ + }\ + }\ + while (0) + +/* Data exported by zfile.c. */ + /* for zfilter.c and ziodev.c */ +extern const uint file_default_buffer_size; + +/* Procedures exported by zfile.c. */ + /* for gs.c */ +FILE *lib_fopen(P1(const char *)); + /* for gsmain.c */ +int lib_file_open(P6(const char *, uint, byte *, uint, uint *, ref *)); + /* for iccinit.c */ +int file_read_string(P3(const byte *, uint, ref *)); + /* for os_open in ziodev.c */ +#ifdef iodev_proc_fopen /* in gxiodev.h */ +int file_open_stream(P6(const char *, uint, const char *, uint, + stream **, iodev_proc_fopen_t)); +#endif + /* for zfilter.c */ +int filter_open(P6(const char *, uint, ref *, const stream_procs _ds *, + const stream_template *, const stream_state *)); + /* for zfileio.c */ +void make_stream_file(P3(ref *, stream *, const char *)); + /* for ziodev.c */ +int file_close_finish(P1(stream *)); +int file_close_disable(P1(stream *)); +int file_close_file(P1(stream *)); + /* for gsmain.c, interp.c */ +int file_close(P1(ref *)); + /* for ziodev.c */ +stream *file_alloc_stream(P2(gs_memory_t *, client_name_t)); + /* for isave.c */ +void file_save(P0()); +/*void file_restore(P1(const alloc_save_t *));*/ + +/* Procedures exported by zfileio.c. */ + /* for ziodev.c */ +int zreadline_from(P5(stream *, byte *, uint, uint *, bool *)); diff --git a/pstoraster/fname.h b/pstoraster/fname.h new file mode 100644 index 0000000000..84e2852eaf --- /dev/null +++ b/pstoraster/fname.h @@ -0,0 +1,38 @@ +/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* fname.h */ +/* File name parsing interface */ +/* Requires gxiodev.h */ + +/* Parsed file name type. Note that the file name may be either a */ +/* gs_string (no terminator) or a C string (null terminator). */ +typedef struct parsed_file_name_s { + gx_io_device *iodev; + const char *fname; + uint len; +} parsed_file_name; +int parse_file_name(P2(const ref *, parsed_file_name *)); +int parse_real_file_name(P3(const ref *, parsed_file_name *, client_name_t)); +int terminate_file_name(P2(parsed_file_name *, client_name_t)); +void free_file_name(P2(parsed_file_name *, client_name_t)); diff --git a/pstoraster/gconf.c b/pstoraster/gconf.c new file mode 100644 index 0000000000..1a6641cc3f --- /dev/null +++ b/pstoraster/gconf.c @@ -0,0 +1,126 @@ +/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gconf.c */ +/* Configuration tables */ +#include "gx.h" +#include "gscdefs.h" /* interface */ +#include "gconfig.h" /* for #defines */ +/* + * Since we only declare variables of type gx_device *, + * it should be sufficient to define struct gx_device_s as + * an abstract (undefined) structure. However, the VAX VMS compiler + * isn't happy with this, so we have to include the full definition. + */ +#include "gxdevice.h" +#include "gxiodev.h" + +/* + * The makefile generates the file gconfig.h, which consists of + * lines of the form + * device_(gs_xxx_device) + * for each installed device; + * emulator_("emulator") + * for each known emulator; + * init_(gs_xxx_init) + * for each initialization procedure; + * io_device_(gs_iodev_xxx) + * for each known IODevice; + * oper_(xxx_op_defs) + * for each operator option; + * psfile_("gs_xxxx.ps") + * for each optional initialization file. + * + * We include this file multiple times to generate various different + * source structures. (It's a hack, but we haven't come up with anything + * more satisfactory.) + */ + +/* ---------------- Resources (devices, inits, IODevices) ---------------- */ + +/* Declare devices, init procedures, and IODevices as extern. */ +#define device_(dev) extern far_data gx_device dev; +#define init_(proc) extern void proc(P1(gs_memory_t *)); +#define io_device_(iodev) extern gx_io_device iodev; +#include "gconfig.h" +#undef init_ +#undef io_device_ +#undef device_ + +/* Set up the initialization procedure table. */ +extern_gx_init_table(); +#define init_(proc) proc, +void (*gx_init_table[])(P1(gs_memory_t *)) = { +#include "gconfig.h" + 0 +}; +#undef init_ + +/* Set up the IODevice table. The first entry must be %os%, */ +/* since it is the default for files with no explicit device specified. */ +extern_gx_io_device_table(); +extern gx_io_device gs_iodev_os; +#define io_device_(iodev) &iodev, +gx_io_device *gx_io_device_table[] = { + &gs_iodev_os, +#include "gconfig.h" + 0 +}; +#undef io_device_ +uint gx_io_device_table_count = countof(gx_io_device_table) - 1; + +/* Set up the device table. */ +#define device_(dev) &dev, +private const gx_device *gx_device_list[] = { +#include "gconfig.h" + 0 +}; +#undef device_ + +/* + * Allocate structure descriptors for the devices. + * We can't fill in the structure sizes, because we don't know them + * statically, and we also don't know statically which devices are + * forwarders; so we fill all of this in when we need to + * (in gs_copydevice in gsdevice.c). + */ +#define device_(dev) { 0 }, +/* Because of a bug in the Borland C++ 4.5 compiler, */ +/* we can't declare the following far_data but not static. */ +static /*private*/ far_data gs_memory_struct_type_t gx_device_st_list[] = { +#include "gconfig.h" + { 0 } +}; +#undef device_ + +/* Return the list of device prototypes, the list of their structure */ +/* descriptors, and (as the value) the length of the lists. */ +extern_gs_lib_device_list(); +int +gs_lib_device_list(const gx_device ***plist, gs_memory_struct_type_t **pst) +{ if ( plist != 0 ) + *plist = gx_device_list; + if ( pst != 0 ) + *pst = gx_device_st_list; + return countof(gx_device_list) - 1; +} diff --git a/pstoraster/gconfig.h b/pstoraster/gconfig.h new file mode 100644 index 0000000000..4988155ff2 --- /dev/null +++ b/pstoraster/gconfig.h @@ -0,0 +1,196 @@ +/* + * "$Id$" + * + * GNU GhostScript configuration file for the Common UNIX Printing + * System (CUPS). + * + * This file is normally generated by a lot of echogs and genconf + * commands... + * + * Copyright 1997-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#include + +#ifdef device_ +device_(gs_cups_device) +device_(gs_nullpage_device) +#endif +#ifdef oper_ +# ifdef HAVE_LIBZ +oper_(zfzlib_op_defs) +# endif /* HAVE_LIBZ */ +oper_(zcie_l2_op_defs) +oper_(zcrd_l2_op_defs) +oper_(zfont0_op_defs) +oper_(zchar2_op_defs) +# ifdef HAVE_LIBJPEG +oper_(zfdcte_op_defs) +oper_(zfdctd_op_defs) +# endif /* HAVE_LIBJPEG */ +oper_(zdevice2_l2_op_defs) +oper_(ziodev2_l2_op_defs) +oper_(zmedia2_l2_op_defs) +#endif +#ifdef io_device_ +io_device_(gs_iodev_null) +io_device_(gs_iodev_ram) +io_device_(gs_iodev_calendar) +#endif +#ifdef psfile_ +psfile_("gs_setpd.ps") +#endif +#ifdef oper_ +oper_(zbseq_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_btokn.ps") +#endif +#ifdef init_ +init_(gs_gscolor1_init) +#endif +#ifdef oper_ +oper_(zcolor1_op_defs) +oper_(zht1_op_defs) +oper_(zupath_l2_op_defs) +oper_(zvmem2_op_defs) +oper_(ireclaim_l2_op_defs) +oper_(zchar2_l2_op_defs) +oper_(zdps1_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_dps1.ps") +#endif +#ifdef oper_ +oper_(zfdecode_op_defs) +oper_(zfilter2_op_defs) +oper_(zarith_op_defs) +oper_(zarray_op_defs) +oper_(zcontrol_op_defs) +oper_(zdict_op_defs) +oper_(zfile_op_defs) +oper_(zfileio_op_defs) +oper_(zfilter_op_defs) +oper_(zfproc_op_defs) +oper_(zgeneric_op_defs) +oper_(ziodev_op_defs) +oper_(zmath_op_defs) +oper_(zmisc_op_defs) +oper_(zpacked_op_defs) +oper_(zrelbit_op_defs) +oper_(zstack_op_defs) +oper_(zstring_op_defs) +oper_(zsysvm_op_defs) +oper_(ztoken_op_defs) +oper_(ztype_op_defs) +oper_(zusparam_op_defs) +oper_(zvmem_op_defs) +oper_(zchar_op_defs) +oper_(zcolor_op_defs) +oper_(zdevice_op_defs) +oper_(zfont_op_defs) +oper_(zfont2_op_defs) +oper_(zgstate_op_defs) +oper_(zht_op_defs) +oper_(zmatrix_op_defs) +oper_(zpaint_op_defs) +oper_(zpath_op_defs) +#endif +#ifdef io_device_ +io_device_(gs_iodev_stdin) +io_device_(gs_iodev_stdout) +io_device_(gs_iodev_stderr) +io_device_(gs_iodev_lineedit) +io_device_(gs_iodev_statementedit) +#endif +#ifdef oper_ +oper_(zfbcp_op_defs) +oper_(zhsb_op_defs) +oper_(zpath1_op_defs) +oper_(zchar1_op_defs) +oper_(zfont1_op_defs) +oper_(zmisc1_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_type1.ps") +#endif +#ifdef emulator_ +emulator_("PostScript") +emulator_("PostScriptLevel1") +#endif +#ifdef oper_ +oper_(zpcolor_l2_op_defs) +oper_(zmisc2_op_defs) +oper_(zcolor2_l2_op_defs) +oper_(zcsindex_l2_op_defs) +oper_(zht2_l2_op_defs) +oper_(zimage2_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_lev2.ps") +psfile_("gs_res.ps") +#endif +#ifdef oper_ +oper_(zcssepr_l2_op_defs) +oper_(zfilterx_op_defs) +#endif +#ifdef emulator_ +emulator_("PostScriptLevel2") +#endif +#ifdef psfile_ +psfile_("gs_mex_e.ps") +psfile_("gs_mro_e.ps") +psfile_("gs_pdf_e.ps") +psfile_("gs_wan_e.ps") +psfile_("gs_pdf.ps") +psfile_("gs_l2img.ps") +psfile_("pdf_base.ps") +psfile_("pdf_draw.ps") +psfile_("pdf_font.ps") +psfile_("pdf_main.ps") +psfile_("pdf_sec.ps") +psfile_("pdf_2ps.ps") +#endif +#ifdef emulator_ +emulator_("PDF") +#endif +#ifdef io_device_ +io_device_(gs_iodev_pipe) +#endif +#ifdef oper_ +oper_(zchar42_op_defs) +oper_(zfont42_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_typ42.ps") +psfile_("gs_ttf.ps") +#endif +#ifdef init_ +init_(gs_climag_init) +init_(gs_clpath_init) +init_(gs_gscolor_init) +init_(gs_roplib_init) +#endif +#define GS_LIB_DEFAULT DATADIR "/ghostscript:" DATADIR "/fonts" +#define GS_DOCDIR DATADIR "/ghostscript" +#define GS_INIT "gs_init.ps" + +/* + * End of "$Id$". + */ diff --git a/pstoraster/gconfigv.h b/pstoraster/gconfigv.h new file mode 100644 index 0000000000..c2f16d45d1 --- /dev/null +++ b/pstoraster/gconfigv.h @@ -0,0 +1,3 @@ +#define USE_ASM (-0) +#define USE_FPU (2-0) +#define EXTEND_NAMES 0 diff --git a/pstoraster/gdebug.h b/pstoraster/gdebug.h new file mode 100644 index 0000000000..aeba8a7aaf --- /dev/null +++ b/pstoraster/gdebug.h @@ -0,0 +1,117 @@ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdebug.h */ +/* Debugging machinery definitions */ + +#ifndef gdebug_INCLUDED +# define gdebug_INCLUDED + +/* Define the array of debugging flags, indexed by character code. */ +extern char gs_debug[128]; +#define gs_debug_c(c)\ + ((c)>='a' && (c)<='z' ? gs_debug[c] | gs_debug[(c)^32] : gs_debug[c]) +#ifdef DEBUG +# define gs_if_debug_c(c) gs_debug_c(c) +#else +# define gs_if_debug_c(c) 0 +#endif +/* Define an alias for a specialized debugging flag */ +/* that used to be a separate variable. */ +#define gs_log_errors gs_debug['#'] + +/* If debugging, direct all error output to gs_debug_out. */ +extern FILE *gs_debug_out; +#ifdef DEBUG +#undef dstderr +#define dstderr gs_debug_out +#undef estderr +#define estderr gs_debug_out +#endif + +/* Redefine eprintf_program_name and lprintf_file_and_line as procedures */ +/* so one can set breakpoints on them. */ +#undef eprintf_program_name +extern void eprintf_program_name(P2(FILE *, const char *)); +#undef lprintf_file_and_line +extern void lprintf_file_and_line(P3(FILE *, const char *, int)); + +/* Insert code conditionally if debugging. */ +#ifdef DEBUG +# define do_debug(x) x +#else +# define do_debug(x) +#endif + +/* Debugging printout macros. */ +#ifdef DEBUG +# define if_debug0(c,s)\ + if (gs_debug_c(c)) dprintf(s) +# define if_debug1(c,s,a1)\ + if (gs_debug_c(c)) dprintf1(s,a1) +# define if_debug2(c,s,a1,a2)\ + if (gs_debug_c(c)) dprintf2(s,a1,a2) +# define if_debug3(c,s,a1,a2,a3)\ + if (gs_debug_c(c)) dprintf3(s,a1,a2,a3) +# define if_debug4(c,s,a1,a2,a3,a4)\ + if (gs_debug_c(c)) dprintf4(s,a1,a2,a3,a4) +# define if_debug5(c,s,a1,a2,a3,a4,a5)\ + if (gs_debug_c(c)) dprintf5(s,a1,a2,a3,a4,a5) +# define if_debug6(c,s,a1,a2,a3,a4,a5,a6)\ + if (gs_debug_c(c)) dprintf6(s,a1,a2,a3,a4,a5,a6) +# define if_debug7(c,s,a1,a2,a3,a4,a5,a6,a7)\ + if (gs_debug_c(c)) dprintf7(s,a1,a2,a3,a4,a5,a6,a7) +# define if_debug8(c,s,a1,a2,a3,a4,a5,a6,a7,a8)\ + if (gs_debug_c(c)) dprintf8(s,a1,a2,a3,a4,a5,a6,a7,a8) +# define if_debug9(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9)\ + if (gs_debug_c(c)) dprintf9(s,a1,a2,a3,a4,a5,a6,a7,a8,a9) +# define if_debug10(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)\ + if (gs_debug_c(c)) dprintf10(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) +# define if_debug11(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)\ + if (gs_debug_c(c)) dprintf11(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) +# define if_debug12(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)\ + if (gs_debug_c(c)) dprintf12(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) +#else +# define if_debug0(c,s) DO_NOTHING +# define if_debug1(c,s,a1) DO_NOTHING +# define if_debug2(c,s,a1,a2) DO_NOTHING +# define if_debug3(c,s,a1,a2,a3) DO_NOTHING +# define if_debug4(c,s,a1,a2,a3,a4) DO_NOTHING +# define if_debug5(c,s,a1,a2,a3,a4,a5) DO_NOTHING +# define if_debug6(c,s,a1,a2,a3,a4,a5,a6) DO_NOTHING +# define if_debug7(c,s,a1,a2,a3,a4,a5,a6,a7) DO_NOTHING +# define if_debug8(c,s,a1,a2,a3,a4,a5,a6,a7,a8) DO_NOTHING +# define if_debug9(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9) DO_NOTHING +# define if_debug10(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) DO_NOTHING +# define if_debug11(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11) DO_NOTHING +# define if_debug12(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12) DO_NOTHING +#endif + +/* Debugging support procedures in gsmisc.c */ +void debug_dump_bytes(P3(const byte *from, const byte *to, + const char *msg)); +void debug_dump_bitmap(P4(const byte *from, uint raster, uint height, + const char *msg)); +void debug_print_string(P2(const byte *str, uint len)); + +#endif /* gdebug_INCLUDED */ diff --git a/pstoraster/gdevabuf.c b/pstoraster/gdevabuf.c new file mode 100644 index 0000000000..11e5090831 --- /dev/null +++ b/pstoraster/gdevabuf.c @@ -0,0 +1,355 @@ +/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevabuf.c */ +/* Alpha-buffering memory devices */ +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +/* ================ Alpha devices ================ */ + +/* + * These devices store 2 or 4 bits of alpha. They are a hybrid of a + * monobit device (for color mapping) and a 2- or 4-bit device (for painting). + * Currently, we only use them for character rasterizing, but they might be + * useful for other things someday. + */ + +/* We can't initialize the device descriptor statically very well, */ +/* so we patch up the image2 or image4 descriptor. */ +private dev_proc_map_rgb_color(mem_alpha_map_rgb_color); +private dev_proc_map_color_rgb(mem_alpha_map_color_rgb); +private dev_proc_map_rgb_alpha_color(mem_alpha_map_rgb_alpha_color); +private dev_proc_get_alpha_bits(mem_alpha_get_alpha_bits); +private dev_proc_copy_alpha(mem_alpha_copy_alpha); + +void +gs_make_mem_alpha_device(gx_device_memory *adev, gs_memory_t *mem, + gx_device *target, int alpha_bits) +{ gs_make_mem_device(adev, gdev_mem_device_for_bits(alpha_bits), + mem, 0, target); + /* This is a black-and-white device ... */ + adev->color_info = gdev_mem_device_for_bits(1)->color_info; + /* ... but it has multiple bits per pixel ... */ + adev->color_info.depth = alpha_bits; + /* ... and different color mapping. */ + set_dev_proc(adev, map_rgb_color, mem_alpha_map_rgb_color); + set_dev_proc(adev, map_color_rgb, mem_alpha_map_color_rgb); + set_dev_proc(adev, map_rgb_alpha_color, mem_alpha_map_rgb_alpha_color); + set_dev_proc(adev, get_alpha_bits, mem_alpha_get_alpha_bits); + set_dev_proc(adev, copy_alpha, mem_alpha_copy_alpha); +} + +/* Reimplement color mapping. */ +private gx_color_index +mem_alpha_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g, + gx_color_value b) +{ gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b); + return (color == 0 || color == gx_no_color_index ? color : + (gx_color_index)((1 << mdev->log2_alpha_bits) - 1)); +} +private int +mem_alpha_map_color_rgb(gx_device *dev, gx_color_index color, + gx_color_value prgb[3]) +{ return + gx_forward_map_color_rgb(dev, + (color == 0 ? color : (gx_color_index)1), + prgb); +} +private gx_color_index +mem_alpha_map_rgb_alpha_color(gx_device *dev, gx_color_value r, + gx_color_value g, gx_color_value b, gx_color_value alpha) +{ gx_color_index color = gx_forward_map_rgb_color(dev, r, g, b); + return (color == 0 || color == gx_no_color_index ? color : + (gx_color_index)(alpha >> (gx_color_value_bits - + mdev->log2_alpha_bits))); +} +private int +mem_alpha_get_alpha_bits(gx_device *dev, graphics_object_type type) +{ return 1 << mdev->log2_alpha_bits; +} +/* Implement alpha copying. */ +private int +mem_alpha_copy_alpha(gx_device *dev, const byte *data, int data_x, + int raster, gx_bitmap_id id, int x, int y, int width, int height, + gx_color_index color, int depth) +{ /* Just use copy_color. */ + return (color == 0 ? + (*dev_proc(dev, fill_rectangle))(dev, x, y, width, height, + color) : + (*dev_proc(dev, copy_color))(dev, data, data_x, raster, id, + x, y, width, height)); +} + +/* ================ Alpha-buffer device ================ */ + +/* + * This device converts graphics sampled at a higher resolution to + * alpha values at a lower resolution. It does this by accumulating + * the bits of a band and then converting the band to alphas. + * In order to make this work, the client of the device must promise + * only to visit each band at most once, except possibly for a single + * scan line overlapping the adjacent band, and must promise only to write + * a single color into the output. In particular, this works + * within a single call on gx_fill_path (if the fill loop is constrained + * to process bands of limited height on each pass) or a single masked image + * scanned in Y order, but not across such calls and not for other + * kinds of painting operations. + * + * We implement this device as a subclass of a monobit memory device. + * (We put its state in the definition of gx_device_memory just because + * actual subclassing introduces a lot of needless boilerplate.) + * We only allocate enough bits for one band. The height of the band + * must be a multiple of the Y scale factor; the minimum height + * of the band is twice the Y scale factor. + * + * The bits in storage are actually a sliding window on the true + * oversampled image. To avoid having to copy the bits around when we + * move the window, we adjust the mapping between the client's Y values + * and our own, as follows: + * Client Stored + * ------ ------ + * y0..y0+m-1 n-m..n-1 + * y0+m..y0+n-1 0..n-m-1 + * where n and m are multiples of the Y scale factor and 0 <= m <= n <= + * the height of the band. (In the device structure, m is called + * mapped_start and n is called mapped_height.) This allows us to slide + * the window incrementally in either direction without copying any bits. + */ + +/* Procedures */ +private dev_proc_close_device(mem_abuf_close); +private dev_proc_copy_mono(mem_abuf_copy_mono); +private dev_proc_fill_rectangle(mem_abuf_fill_rectangle); + +/* The device descriptor. */ +private const gx_device_memory far_data mem_alpha_buffer_device = + mem_device("image(alpha buffer)", 0, 1, + gx_forward_map_rgb_color, gx_forward_map_color_rgb, + mem_abuf_copy_mono, gx_default_copy_color, mem_abuf_fill_rectangle, + gx_no_strip_copy_rop); + +/* Make an alpha-buffer memory device. */ +/* We use abuf instead of alpha_buffer because */ +/* gcc under VMS only retains 23 characters of procedure names. */ +void +gs_make_mem_abuf_device(gx_device_memory *adev, gs_memory_t *mem, + gx_device *target, const gs_log2_scale_point *pscale, + int alpha_bits, int mapped_x) +{ gs_make_mem_device(adev, &mem_alpha_buffer_device, mem, 0, target); + adev->max_fill_band = 1 << pscale->y; + adev->log2_scale = *pscale; + adev->log2_alpha_bits = alpha_bits >> 1; /* works for 1,2,4 */ + adev->mapped_x = mapped_x; + set_dev_proc(adev, close_device, mem_abuf_close); +} + +/* Test whether a device is an alpha-buffering device. */ +bool +gs_device_is_abuf(const gx_device *dev) +{ /* We can't just compare the procs, or even an individual proc, */ + /* because we might be tracing. Instead, check the identity of */ + /* the device name. */ + return dev->dname == mem_alpha_buffer_device.dname; +} + +/* Internal routine to flush a block of the buffer. */ +/* A block is a group of scan lines whose initial Y is a multiple */ +/* of the Y scale and whose height is equal to the Y scale. */ +private int +abuf_flush_block(gx_device_memory *adev, int y) +{ gx_device *target = adev->target; + int block_height = 1 << adev->log2_scale.y; + int alpha_bits = 1 << adev->log2_alpha_bits; + int ddepth = + (adev->width >> adev->log2_scale.x) << adev->log2_alpha_bits; + uint draster = bitmap_raster(ddepth); + int buffer_y = y - adev->mapped_y + adev->mapped_start; + byte *bits; + + if ( buffer_y >= adev->height ) + buffer_y -= adev->height; + bits = scan_line_base(adev, buffer_y); + { /* + * Many bits are typically zero. Save time by computing + * an accurate X bounding box before compressing. + * Unfortunately, in order to deal with alpha nibble swapping + * (see gsbitops.c), we can't expand the box only to pixel + * boundaries: + int alpha_mask = -1 << adev->log2_alpha_bits; + * Instead, we must expand it to byte boundaries, + */ + int alpha_mask = ~7; + gs_int_rect bbox; + int width; + + bits_bounding_box(bits, block_height, adev->raster, &bbox); + bbox.p.x &= alpha_mask; + bbox.q.x = (bbox.q.x + ~alpha_mask) & alpha_mask; + width = bbox.q.x - bbox.p.x; + bits_compress_scaled(bits, bbox.p.x, width, block_height, + adev->raster, bits, draster, &adev->log2_scale, + adev->log2_alpha_bits); + return (*dev_proc(target, copy_alpha))(target, + bits, 0, draster, gx_no_bitmap_id, + (adev->mapped_x + bbox.p.x) >> + adev->log2_scale.x, + y >> adev->log2_scale.y, + width >> adev->log2_scale.x, 1, + adev->save_color, alpha_bits); + } +} +/* Flush the entire buffer. */ +private int +abuf_flush(gx_device_memory *adev) +{ int y, code = 0; + int block_height = 1 << adev->log2_scale.y; + for ( y = 0; y < adev->mapped_height; y += block_height ) + if ( (code = abuf_flush_block(adev, adev->mapped_y + y)) < 0 ) + return code; + adev->mapped_height = adev->mapped_start = 0; + return 0; +} + +/* Close the device, flushing the buffer. */ +private int +mem_abuf_close(gx_device *dev) +{ int code = abuf_flush(mdev); + if ( code < 0 ) + return code; + return mem_close(dev); +} + +/* + * Framework for mapping a requested imaging operation to the buffer. + * For now, we assume top-to-bottom transfers and use a very simple algorithm. + */ +typedef struct y_transfer_s { + int y_next; + int height_left; + int transfer_y; + int transfer_height; +} y_transfer; +private void near +y_transfer_init(y_transfer *pyt, gx_device *dev, int ty, int th) +{ int bh = 1 << mdev->log2_scale.y; + if ( ty < mdev->mapped_y || ty > mdev->mapped_y + mdev->mapped_height ) + { abuf_flush(mdev); + mdev->mapped_y = ty & -bh; + mdev->mapped_height = bh; + memset(scan_line_base(mdev, 0), 0, bh * mdev->raster); + } + pyt->y_next = ty; + pyt->height_left = th; + pyt->transfer_height = 0; +} +/* while ( yt.height_left > 0 ) { y_transfer_next(&yt, mdev); ... } */ +private void near +y_transfer_next(y_transfer *pyt, gx_device *dev) +{ int my = mdev->mapped_y, mh = mdev->mapped_height; + int ms = mdev->mapped_start; + int ty = pyt->y_next += pyt->transfer_height; + int th = pyt->height_left; + int bh = 1 << mdev->log2_scale.y; + /* From here on, we know that my <= ty <= my + mh. */ + int tby, tbh; + if ( ty == my + mh ) + { /* Add a new block at my1. */ + if ( mh == mdev->height ) + { abuf_flush_block(mdev, my); + mdev->mapped_y = my += bh; + if ( (mdev->mapped_start = ms += bh) == mh ) + mdev->mapped_start = ms = 0; + } + else + { /* Because we currently never extend backwards, */ + /* we know we can't wrap around in this case. */ + mdev->mapped_height = mh += bh; + } + memset(scan_line_base(mdev, (ms == 0 ? mh : ms) - bh), + 0, bh * mdev->raster); + } + /* Now we know that my <= ty < my + mh. */ + tby = ty - my + ms; + if ( tby < mdev->height ) + { tbh = mdev->height - ms; + if ( tbh > mh ) tbh = mh; + tbh -= tby - ms; + } + else /* wrap around */ + { tby -= mdev->height; + tbh = ms + mh - dev->height - tby; + } + if_debug7('v', "[v]my=%d, mh=%d, ms=%d, ty=%d, th=%d, tby=%d, tbh=%d\n", + my, mh, ms, ty, th, tby, tbh); + if ( tbh > th ) tbh = th; + pyt->height_left = th - tbh; + pyt->transfer_y = tby; + pyt->transfer_height = tbh; +} + +/* Copy a monobit image. */ +private int +mem_abuf_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ y_transfer yt; + if ( zero != gx_no_color_index || one == gx_no_color_index ) + return_error(gs_error_undefinedresult); + x -= mdev->mapped_x; + fit_copy_xwh(dev, base, sourcex, sraster, id, x, y, w, h); /* don't limit y */ + mdev->save_color = one; + y_transfer_init(&yt, dev, y, h); + while ( yt.height_left > 0 ) + { y_transfer_next(&yt, dev); + (*dev_proc(&mem_mono_device, copy_mono))(dev, + base + (yt.y_next - y) * sraster, + sourcex, sraster, gx_no_bitmap_id, + x, yt.transfer_y, w, yt.transfer_height, + gx_no_color_index, (gx_color_index)1); + } + return 0; +} + +/* Fill a rectangle. */ +private int +mem_abuf_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ y_transfer yt; + x -= mdev->mapped_x; + fit_fill_xyw(dev, x, y, w, h); /* don't limit h */ + /* or check w <= 0, h <= 0 */ + mdev->save_color = color; + y_transfer_init(&yt, dev, y, h); + while ( yt.height_left > 0 ) + { y_transfer_next(&yt, dev); + (*dev_proc(&mem_mono_device, fill_rectangle))(dev, + x, yt.transfer_y, w, yt.transfer_height, + (gx_color_index)1); + } + return 0; +} diff --git a/pstoraster/gdevcups.c b/pstoraster/gdevcups.c new file mode 100644 index 0000000000..1d4b8f202f --- /dev/null +++ b/pstoraster/gdevcups.c @@ -0,0 +1,2459 @@ +/* + * "$Id$" + * + * GNU Ghostscript raster output driver for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1993-1999 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636-3111 USA + * + * Voice: (301) 373-9603 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This code and any derivative of it may be used and distributed + * freely under the terms of the GNU General Public License when + * used with GNU Ghostscript or its derivatives. Use of the code + * (or any derivative of it) with software other than GNU + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + * + * Contents: + * + * cups_close() - Close the output file. + * cups_get_matrix() - Generate the default page matrix. + * cups_get_params() - Get pagedevice parameters. + * cups_map_color_rgb() - Map a color index to an RGB color. + * cups_map_rgb_color() - Map an RGB color to a color index. We map the + * RGB color to the output colorspace & bits (we + * figure out the format when we output a page). + * cups_open() - Open the output file and initialize things. + * cups_print_pages() - Send one or more pages to the output file. + * cups_put_params() - Set pagedevice parameters. + * cups_set_color_info() - Set the color information structure based on + * the required output. + * cups_print_chunked() - Print a page of chunked pixels. + * cups_print_banded() - Print a page of banded pixels. + * cups_print_planar() - Print a page of planar pixels. + */ + +/* + * Include necessary headers... + */ + +#include "std.h" /* to stop stdlib.h redefining types */ +#include "gdevprn.h" +#include "gsparam.h" + +#include +#include +#include +#include + + +/* + * Macros... + */ + +#define x_dpi (pdev->HWResolution[0]) +#define y_dpi (pdev->HWResolution[1]) +#define cups ((gx_device_cups *)pdev) + +/* + * Macros from ; we can't include because it also + * defines DEBUG, one of our flags to insert various debugging code. + */ + +#ifndef max +# define max(a,b) ((a)<(b) ? (b) : (a)) +#endif /* !max */ + +#ifndef min +# define min(a,b) ((a)>(b) ? (b) : (a)) +#endif /* !min */ + +#ifndef abs +# define abs(x) ((x)>=0 ? (x) : -(x)) +#endif /* !abs */ + + +/* + * Procedures + */ + +private dev_proc_close_device(cups_close); +private dev_proc_get_initial_matrix(cups_get_matrix); +private int cups_get_params(gx_device *, gs_param_list *); +private dev_proc_map_color_rgb(cups_map_color_rgb); +private dev_proc_map_cmyk_color(cups_map_cmyk_color); +private dev_proc_map_rgb_color(cups_map_rgb_color); +private dev_proc_open_device(cups_open); +private int cups_print_pages(gx_device_printer *, FILE *, int); +private int cups_put_params(gx_device *, gs_param_list *); +private void cups_set_color_info(gx_device *); +private dev_proc_sync_output(cups_sync_output); + +/* + * The device descriptors... + */ + +typedef struct gx_device_cups_s +{ + gx_device_common; /* Standard GhostScript device stuff */ + gx_prn_device_common; /* Standard printer device stuff */ + int page; /* Page number */ + cups_raster_t *stream; /* Raster stream */ + ppd_file_t *ppd; /* PPD file for this printer */ + cups_page_header_t header; /* PostScript page device info */ +} gx_device_cups; + +private gx_device_procs cups_procs = +{ + cups_open, + cups_get_matrix, + cups_sync_output, + gdev_prn_output_page, + cups_close, + cups_map_rgb_color, + cups_map_color_rgb, + NULL, /* fill_rectangle */ + NULL, /* tile_rectangle */ + NULL, /* copy_mono */ + NULL, /* copy_color */ + NULL, /* draw_line */ + gx_default_get_bits, + cups_get_params, + cups_put_params, + NULL, + NULL, /* get_xfont_procs */ + NULL, /* get_xfont_device */ + NULL, /* map_rgb_alpha_color */ + gx_page_device_get_page_device, + NULL, /* get_alpha_bits */ + NULL, /* copy_alpha */ + NULL, /* get_band */ + NULL, /* copy_rop */ + NULL, /* fill_path */ + NULL, /* stroke_path */ + NULL, /* fill_mask */ + NULL, /* fill_trapezoid */ + NULL, /* fill_parallelogram */ + NULL, /* fill_triangle */ + NULL, /* draw_thin_line */ + NULL, /* begin_image */ + NULL, /* image_data */ + NULL, /* end_image */ + NULL, /* strip_tile_rectangle */ + NULL /* strip_copy_rop */ +}; + +gx_device_cups gs_cups_device = +{ + prn_device_body_copies(gx_device_cups, cups_procs, "cups", 85, 110, 100, 100, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, cups_print_pages), + 0, /* page */ + NULL, /* stream */ + NULL, /* ppd */ + { /* header */ + "", /* MediaClass */ + "", /* MediaColor */ + "", /* MediaType */ + "", /* OutputType */ + 0, /* AdvanceDistance */ + CUPS_ADVANCE_NONE, /* AdvanceMedia */ + CUPS_FALSE, /* Collate */ + CUPS_CUT_NONE, /* CutMedia */ + CUPS_FALSE, /* Duplex */ + { 100, 100 }, /* HWResolution */ + { 0, 0, 612, 792 }, /* ImagingBoundingBox */ + CUPS_FALSE, /* InsertSheet */ + CUPS_JOG_NONE, /* Jog */ + CUPS_EDGE_TOP, /* LeadingEdge */ + { 0, 0 }, /* Margins */ + CUPS_FALSE, /* ManualFeed */ + 0, /* MediaPosition */ + 0, /* MediaWeight */ + CUPS_FALSE, /* MirrorPrint */ + CUPS_FALSE, /* NegativePrint */ + 1, /* NumCopies */ + CUPS_ORIENT_0, /* Orientation */ + CUPS_FALSE, /* OutputFaceUp */ + { 612, 792 }, /* PageSize */ + CUPS_FALSE, /* Separations */ + CUPS_FALSE, /* TraySwitch */ + CUPS_FALSE, /* Tumble */ + 850, /* cupsWidth */ + 1100, /* cupsHeight */ + 0, /* cupsMediaType */ + 1, /* cupsBitsPerColor */ + 1, /* cupsBitsPerPixel */ + 107, /* cupsBytesPerLine */ + CUPS_ORDER_CHUNKED, /* cupsColorOrder */ + CUPS_CSPACE_K, /* cupsColorSpace */ + 0, /* cupsCompression */ + 0, /* cupsRowCount */ + 0, /* cupsRowFeed */ + 0 /* cupsRowStep */ + } +}; + +/* + * Color lookup tables... + */ + +static gx_color_value lut_color_rgb[256]; +static unsigned char lut_rgb_color[gx_max_color_value + 1]; +static int cupsHaveProfile = 0; +static int cupsMatrix[3][3][gx_max_color_value + 1]; +static int cupsDensity[gx_max_color_value + 1]; + + +/* + * Local functions... + */ + +static void cups_print_chunked(gx_device_printer *, unsigned char *); +static void cups_print_banded(gx_device_printer *, unsigned char *, + unsigned char *, int); +static void cups_print_planar(gx_device_printer *, unsigned char *, + unsigned char *, int); + +/*static void cups_set_margins(gx_device *);*/ + + +/* + * 'cups_close()' - Close the output file. + */ + +private int +cups_close(gx_device *pdev) /* I - Device info */ +{ +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_close(%08x)\n", pdev); +#endif /* DEBUG */ + + if (cups->stream != NULL) + { + cupsRasterClose(cups->stream); + cups->stream = NULL; + } + +#if 0 /* Can't do this here because put_params() might close the device */ + if (cups->ppd != NULL) + { + ppdClose(cups->ppd); + cups->ppd = NULL; + } +#endif /* 0 */ + + return (gdev_prn_close(pdev)); +} + + +/* + * 'cups_get_matrix()' - Generate the default page matrix. + */ + +private void +cups_get_matrix(gx_device *pdev, /* I - Device info */ + gs_matrix *pmat) /* O - Physical transform matrix */ +{ +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_get_matrix(%08x, %08x)\n", pdev, pmat); +#endif /* DEBUG */ + + /* + * Set the raster width and height... + */ + + cups->header.cupsWidth = cups->width; + cups->header.cupsHeight = cups->height; + + /* + * Set the transform matrix... + */ + + pmat->xx = (float)cups->header.HWResolution[0] / 72.0; + pmat->xy = 0.0; + pmat->yx = 0.0; + pmat->yy = -(float)cups->header.HWResolution[1] / 72.0; + pmat->tx = -(float)cups->header.HWResolution[0] * pdev->HWMargins[0] / 72.0; + pmat->ty = (float)cups->header.HWResolution[1] * + ((float)cups->header.PageSize[1] - pdev->HWMargins[3]) / 72.0; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: width = %d, height = %d\n", cups->width, + cups->height); + fprintf(stderr, "DEBUG: PageSize = [ %d %d ], HWResolution = [ %d %d ]\n", + cups->header.PageSize[0], cups->header.PageSize[1], + cups->header.HWResolution[0], cups->header.HWResolution[1]); + fprintf(stderr, "DEBUG: matrix = [ %.3f %.3f %.3f %.3f %.3f %.3f ]\n", + pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty); +#endif /* DEBUG */ +} + + +/* + * 'cups_get_params()' - Get pagedevice parameters. + */ + +private int /* O - Error status */ +cups_get_params(gx_device *pdev, /* I - Device info */ + gs_param_list *plist) /* I - Parameter list */ +{ + int code; /* Return code */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_get_params(%08x, %08x)\n", pdev, plist); +#endif /* DEBUG */ + + /* + * First process the "standard" page device parameters... + */ + + if ((code = gdev_prn_get_params(pdev, plist)) < 0) + return (code); + + /* + * Then write the CUPS-specific parameters... + */ + + if ((code = param_write_int(plist, "cupsWidth", + (int *)&(cups->header.cupsWidth))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsHeight", + (int *)&(cups->header.cupsHeight))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsMediaType", + (int *)&(cups->header.cupsMediaType))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsBitsPerColor", + (int *)&(cups->header.cupsBitsPerColor))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsBitsPerPixel", + (int *)&(cups->header.cupsBitsPerPixel))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsBytesPerLine", + (int *)&(cups->header.cupsBytesPerLine))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsColorOrder", + (int *)&(cups->header.cupsColorOrder))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsColorSpace", + (int *)&(cups->header.cupsColorSpace))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsCompression", + (int *)&(cups->header.cupsCompression))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsRowCount", + (int *)&(cups->header.cupsRowCount))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsRowFeed", + (int *)&(cups->header.cupsRowFeed))) < 0) + return (code); + + if ((code = param_write_int(plist, "cupsRowStep", + (int *)&(cups->header.cupsRowStep))) < 0) + return (code); + + return (0); +} + + +/* + * 'cups_map_color_rgb()' - Map a color index to an RGB color. + */ + +private int +cups_map_color_rgb(gx_device *pdev, /* I - Device info */ + gx_color_index color, /* I - Color index */ + gx_color_value prgb[3]) /* O - RGB values */ +{ + unsigned char c0, c1, c2, c3; /* Color index components */ + gx_color_value k, divk; /* Black & divisor */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_map_color_rgb(%08x, %d, %08x)\n", pdev, + color, prgb); +#endif /* DEBUG */ + + /* + * Setup the color info data as needed... + */ + + if (pdev->color_info.num_components == 0) + cups_set_color_info(pdev); + +#ifdef DEBUG + fprintf(stderr, "DEBUG: COLOR %08x = ", color); +#endif /* DEBUG */ + + /* + * Extract the color components from the color index... + */ + + switch (cups->header.cupsBitsPerColor) + { + case 1 : + c3 = color & 1; + color >>= 1; + c2 = color & 1; + color >>= 1; + c1 = color & 1; + color >>= 1; + c0 = color; + break; + case 2 : + c3 = color & 3; + color >>= 2; + c2 = color & 3; + color >>= 2; + c2 = color & 3; + color >>= 2; + c0 = color; + break; + case 4 : + c3 = color & 15; + color >>= 4; + c2 = color & 15; + color >>= 4; + c1 = color & 15; + color >>= 4; + c0 = color; + break; + case 8 : + c3 = color & 255; + color >>= 8; + c2 = color & 255; + color >>= 8; + c1 = color & 255; + color >>= 8; + c0 = color; + break; + } + + /* + * Convert the color components to RGB... + */ + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_K : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + prgb[0] = + prgb[1] = + prgb[2] = lut_color_rgb[c3]; + break; + + case CUPS_CSPACE_W : + prgb[0] = + prgb[1] = + prgb[2] = lut_color_rgb[c3]; + break; + + case CUPS_CSPACE_RGB : + prgb[0] = lut_color_rgb[c1]; + prgb[1] = lut_color_rgb[c2]; + prgb[2] = lut_color_rgb[c3]; + break; + + case CUPS_CSPACE_CMY : + prgb[0] = lut_color_rgb[c1]; + prgb[1] = lut_color_rgb[c2]; + prgb[2] = lut_color_rgb[c3]; + break; + + case CUPS_CSPACE_YMC : + prgb[0] = lut_color_rgb[c3]; + prgb[1] = lut_color_rgb[c2]; + prgb[2] = lut_color_rgb[c1]; + break; + + case CUPS_CSPACE_KCMY : + k = lut_color_rgb[c0]; + divk = gx_max_color_value - k; + if (divk == 0) + { + prgb[0] = 0; + prgb[1] = 0; + prgb[2] = 0; + } + else + { + prgb[0] = gx_max_color_value + divk - + gx_max_color_value * c1 / divk; + prgb[1] = gx_max_color_value + divk - + gx_max_color_value * c2 / divk; + prgb[2] = gx_max_color_value + divk - + gx_max_color_value * c3 / divk; + } + break; + + case CUPS_CSPACE_CMYK : + k = lut_color_rgb[c3]; + divk = gx_max_color_value - k; + if (divk == 0) + { + prgb[0] = 0; + prgb[1] = 0; + prgb[2] = 0; + } + else + { + prgb[0] = gx_max_color_value + divk - + gx_max_color_value * c0 / divk; + prgb[1] = gx_max_color_value + divk - + gx_max_color_value * c1 / divk; + prgb[2] = gx_max_color_value + divk - + gx_max_color_value * c2 / divk; + } + break; + + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + k = lut_color_rgb[c3]; + divk = gx_max_color_value - k; + if (divk == 0) + { + prgb[0] = 0; + prgb[1] = 0; + prgb[2] = 0; + } + else + { + prgb[0] = gx_max_color_value + divk - + gx_max_color_value * c2 / divk; + prgb[1] = gx_max_color_value + divk - + gx_max_color_value * c1 / divk; + prgb[2] = gx_max_color_value + divk - + gx_max_color_value * c0 / divk; + } + break; + } + +#ifdef DEBUG + fprintf(stderr, "%d,%d,%d\n", prgb[0], prgb[1], prgb[2]); +#endif /* DEBUG */ + + return (0); +} + + +/* + * 'cups_map_rgb_color()' - Map an RGB color to a color index. We map the + * RGB color to the output colorspace & bits (we + * figure out the format when we output a page). + */ + +private gx_color_index /* O - Color index */ +cups_map_rgb_color(gx_device *pdev, /* I - Device info */ + gx_color_value r, /* I - Red value */ + gx_color_value g, /* I - Green value */ + gx_color_value b) /* I - Blue value */ +{ + gx_color_index i; /* Temporary index */ + gx_color_value ic, im, iy, ik; /* Integral CMYKcm values */ + float divk, /* Black "divisor" */ + diff; /* Average color difference */ + int tc, tm, ty, tk; /* Temporary color values */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_map_rgb_color(%08x, %d, %d, %d)\n", pdev, r, g, b); +#endif /* DEBUG */ + + /* + * Setup the color info data as needed... + */ + + if (pdev->color_info.num_components == 0) + cups_set_color_info(pdev); + + /* + * Do color correction as needed... + */ + + if (cupsHaveProfile) + { + /* + * Compute CMYK values... + */ + + ic = gx_max_color_value - r; + im = gx_max_color_value - g; + iy = gx_max_color_value - b; + ik = min(ic, min(im, iy)); + ic -= ik; + im -= ik; + iy -= ik; + + /* + * Color correct CMY... + */ + + tc = cupsMatrix[0][0][ic] + + cupsMatrix[0][1][im] + + cupsMatrix[0][2][iy] + + ik; + tm = cupsMatrix[1][0][ic] + + cupsMatrix[1][1][im] + + cupsMatrix[1][2][iy] + + ik; + ty = cupsMatrix[2][0][ic] + + cupsMatrix[2][1][im] + + cupsMatrix[2][2][iy] + + ik; + + /* + * Density correct combined CMYK... + */ + + if (tc < 0) + r = gx_max_color_value; + else if (tc > gx_max_color_value) + r = gx_max_color_value - cupsDensity[gx_max_color_value]; + else + r = gx_max_color_value - cupsDensity[tc]; + + if (tm < 0) + g = gx_max_color_value; + else if (tm > gx_max_color_value) + g = gx_max_color_value - cupsDensity[gx_max_color_value]; + else + g = gx_max_color_value - cupsDensity[tm]; + + if (ty < 0) + b = gx_max_color_value; + else if (ty > gx_max_color_value) + b = gx_max_color_value - cupsDensity[gx_max_color_value]; + else + b = gx_max_color_value - cupsDensity[ty]; + } + + /* + * Convert the RGB color to a color index... + */ + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_W : + i = lut_rgb_color[(r * 31 + g * 61 + b * 8) / 100]; + break; + + case CUPS_CSPACE_RGB : + ic = lut_rgb_color[r]; + im = lut_rgb_color[g]; + iy = lut_rgb_color[b]; + + switch (cups->header.cupsBitsPerColor) + { + case 1 : + i = (((ic << 1) | im) << 1) | iy; + break; + case 2 : + i = (((ic << 2) | im) << 2) | iy; + break; + case 4 : + i = (((ic << 4) | im) << 4) | iy; + break; + case 8 : + i = (((ic << 8) | im) << 8) | iy; + break; + } + break; + + case CUPS_CSPACE_K : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + i = lut_rgb_color[gx_max_color_value - (r * 31 + g * 61 + b * 8) / 100]; + break; + + case CUPS_CSPACE_CMY : + if (cups->header.cupsBitsPerColor == 1) + { + ic = lut_rgb_color[gx_max_color_value - r]; + im = lut_rgb_color[gx_max_color_value - g]; + iy = lut_rgb_color[gx_max_color_value - b]; + } + else + { + ic = gx_max_color_value - r; + im = gx_max_color_value - g; + iy = gx_max_color_value - b; + ik = min(ic, min(im, iy)); + + ic = lut_rgb_color[(gx_color_value)((float)(gx_max_color_value - g / 4) / + (float)gx_max_color_value * (float)(ic - ik)) + ik]; + im = lut_rgb_color[(gx_color_value)((float)(gx_max_color_value - b / 4) / + (float)gx_max_color_value * (float)(im - ik)) + ik]; + iy = lut_rgb_color[(gx_color_value)((float)(gx_max_color_value - r / 4) / + (float)gx_max_color_value * (float)(iy - ik)) + ik]; + } + + switch (cups->header.cupsBitsPerColor) + { + case 1 : + i = (((ic << 1) | im) << 1) | iy; + break; + case 2 : + i = (((ic << 2) | im) << 2) | iy; + break; + case 4 : + i = (((ic << 4) | im) << 4) | iy; + break; + case 8 : + i = (((ic << 8) | im) << 8) | iy; + break; + } + break; + + case CUPS_CSPACE_YMC : + if (cups->header.cupsBitsPerColor == 1) + { + ic = lut_rgb_color[gx_max_color_value - r]; + im = lut_rgb_color[gx_max_color_value - g]; + iy = lut_rgb_color[gx_max_color_value - b]; + } + else + { + ic = gx_max_color_value - r; + im = gx_max_color_value - g; + iy = gx_max_color_value - b; + ik = min(ic, min(im, iy)); + + ic = lut_rgb_color[(gx_color_value)((float)(gx_max_color_value - g / 4) / + (float)gx_max_color_value * (float)(ic - ik)) + ik]; + im = lut_rgb_color[(gx_color_value)((float)(gx_max_color_value - b / 4) / + (float)gx_max_color_value * (float)(im - ik)) + ik]; + iy = lut_rgb_color[(gx_color_value)((float)(gx_max_color_value - r / 4) / + (float)gx_max_color_value * (float)(iy - ik)) + ik]; + } + + switch (cups->header.cupsBitsPerColor) + { + case 1 : + i = (((iy << 1) | im) << 1) | ic; + break; + case 2 : + i = (((iy << 2) | im) << 2) | ic; + break; + case 4 : + i = (((iy << 4) | im) << 4) | ic; + break; + case 8 : + i = (((iy << 8) | im) << 8) | ic; + break; + } + break; + + case CUPS_CSPACE_CMYK : + ic = gx_max_color_value - r; + im = gx_max_color_value - g; + iy = gx_max_color_value - b; + ik = min(ic, min(im, iy)); + + if (ik > 0) + { + diff = 1.0 - (float)(max(ic, max(im, iy)) - ik) / + (float)gx_max_color_value; + ik = (int)(diff * (float)ik); + } + + if (ik == gx_max_color_value) + { + ik = lut_rgb_color[ik]; + ic = 0; + im = 0; + iy = 0; + } + else if (cups->header.cupsBitsPerColor == 1) + { + ic = lut_rgb_color[ic - ik]; + im = lut_rgb_color[im - ik]; + iy = lut_rgb_color[iy - ik]; + ik = lut_rgb_color[ik]; + } + else + { + divk = (float)gx_max_color_value / (float)(gx_max_color_value - ik); + tc = (float)(ic - ik) * divk; + tm = (float)(im - ik) * divk; + ty = (float)(iy - ik) * divk; + + if (tc >= gx_max_color_value) + ic = lut_rgb_color[gx_max_color_value]; + else + ic = lut_rgb_color[tc]; + + if (tm >= gx_max_color_value) + im = lut_rgb_color[gx_max_color_value]; + else + im = lut_rgb_color[tm]; + + if (ty >= gx_max_color_value) + iy = lut_rgb_color[gx_max_color_value]; + else + iy = lut_rgb_color[ty]; + + ik = lut_rgb_color[ik]; + } + + switch (cups->header.cupsBitsPerColor) + { + case 1 : + i = (((((ic << 1) | im) << 1) | iy) << 1) | ik; + break; + case 2 : + i = (((((ic << 2) | im) << 2) | iy) << 2) | ik; + break; + case 4 : + i = (((((ic << 4) | im) << 4) | iy) << 4) | ik; + break; + case 8 : + i = (((((ic << 8) | im) << 8) | iy) << 8) | ik; + break; + } + + if (gs_log_errors > 1) + fprintf(stderr, "DEBUG: CMY (%d,%d,%d) -> CMYK %08.8x (%d,%d,%d,%d)\n", + r, g, b, i, ic, im, iy, ik); + break; + + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + ic = gx_max_color_value - r; + im = gx_max_color_value - g; + iy = gx_max_color_value - b; + ik = min(ic, min(im, iy)); + + if (ik > 0) + { + diff = 1.0 - (float)(max(ic, max(im, iy)) - ik) / + (float)gx_max_color_value; + ik = (int)(diff * (float)ik); + } + + if (ik == gx_max_color_value) + { + ik = lut_rgb_color[ik]; + ic = 0; + im = 0; + iy = 0; + } + else if (cups->header.cupsBitsPerColor == 1) + { + ic = lut_rgb_color[ic - ik]; + im = lut_rgb_color[im - ik]; + iy = lut_rgb_color[iy - ik]; + ik = lut_rgb_color[ik]; + } + else + { + divk = (float)gx_max_color_value / (float)(gx_max_color_value - ik); + tc = (float)(ic - ik) * divk; + tm = (float)(im - ik) * divk; + ty = (float)(iy - ik) * divk; + + if (tc >= gx_max_color_value) + ic = lut_rgb_color[gx_max_color_value]; + else + ic = lut_rgb_color[tc]; + + if (tm >= gx_max_color_value) + im = lut_rgb_color[gx_max_color_value]; + else + im = lut_rgb_color[tm]; + + if (ty >= gx_max_color_value) + iy = lut_rgb_color[gx_max_color_value]; + else + iy = lut_rgb_color[ty]; + + ik = lut_rgb_color[ik]; + } + + switch (cups->header.cupsBitsPerColor) + { + case 1 : + i = (((((iy << 1) | im) << 1) | ic) << 1) | ik; + break; + case 2 : + i = (((((iy << 2) | im) << 2) | ic) << 2) | ik; + break; + case 4 : + i = (((((iy << 4) | im) << 4) | ic) << 4) | ik; + break; + case 8 : + i = (((((iy << 8) | im) << 8) | ic) << 8) | ik; + break; + } + break; + + case CUPS_CSPACE_KCMYcm : + if (cups->header.cupsBitsPerColor == 1) + { + ic = gx_max_color_value - r; + im = gx_max_color_value - g; + iy = gx_max_color_value - b; + ik = min(ic, min(im, iy)); + + if (ik > 0) + { + diff = 1.0 - (float)(max(ic, max(im, iy)) - ik) / (float)ik; + ik = (int)(diff * (float)ik); + } + + ic = lut_rgb_color[ic - ik]; + im = lut_rgb_color[im - ik]; + iy = lut_rgb_color[iy - ik]; + ik = lut_rgb_color[ik]; + if (ik) + i = 32; + else if (ic && im) + i = 17; + else if (ic && iy) + i = 6; + else if (im && iy) + i = 12; + else if (ic) + i = 16; + else if (im) + i = 8; + else if (iy) + i = 4; + else + i = 0; + break; + } + + case CUPS_CSPACE_KCMY : + ic = gx_max_color_value - r; + im = gx_max_color_value - g; + iy = gx_max_color_value - b; + ik = min(ic, min(im, iy)); + + if (ik > 0) + { + diff = 1.0 - (float)(max(ic, max(im, iy)) - ik) / + (float)gx_max_color_value; + ik = (int)(diff * (float)ik); + } + + if (ik == gx_max_color_value) + { + ik = lut_rgb_color[ik]; + ic = 0; + im = 0; + iy = 0; + } + else if (cups->header.cupsBitsPerColor == 1) + { + ic = lut_rgb_color[ic - ik]; + im = lut_rgb_color[im - ik]; + iy = lut_rgb_color[iy - ik]; + ik = lut_rgb_color[ik]; + } + else + { + divk = (float)gx_max_color_value / (float)(gx_max_color_value - ik); + tc = (float)(ic - ik) * divk; + tm = (float)(im - ik) * divk; + ty = (float)(iy - ik) * divk; + + if (tc >= gx_max_color_value) + ic = lut_rgb_color[gx_max_color_value]; + else + ic = lut_rgb_color[tc]; + + if (tm >= gx_max_color_value) + im = lut_rgb_color[gx_max_color_value]; + else + im = lut_rgb_color[tm]; + + if (ty >= gx_max_color_value) + iy = lut_rgb_color[gx_max_color_value]; + else + iy = lut_rgb_color[ty]; + + ik = lut_rgb_color[ik]; + } + + switch (cups->header.cupsBitsPerColor) + { + case 1 : + i = (((((ik << 1) | ic) << 1) | im) << 1) | iy; + break; + case 2 : + i = (((((ik << 2) | ic) << 2) | im) << 2) | iy; + break; + case 4 : + i = (((((ik << 4) | ic) << 4) | im) << 4) | iy; + break; + case 8 : + i = (((((ik << 8) | ic) << 8) | im) << 8) | iy; + break; + } + break; + } + +#ifdef DEBUG + fprintf(stderr, "DEBUG: RGB %d,%d,%d = %08x\n", r, g, b, i); +#endif /* DEBUG */ + + return (i); +} + + +/* + * 'cups_open()' - Open the output file and initialize things. + */ + +private int /* O - Error status */ +cups_open(gx_device *pdev) /* I - Device info */ +{ + int code; /* Return status */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_open(%08x)\n", pdev); +#endif /* DEBUG */ + + if (cups->page == 0) + { + fputs("INFO: Processing page 1...\n", stderr); + cups->page = 1; + } + + if (pdev->color_info.num_components == 0) + cups_set_color_info(pdev); + + if ((code = gdev_prn_open(pdev)) != 0) + return (code); + + if (cups->ppd == NULL) + cups->ppd = ppdOpenFile(getenv("PPD")); + + return (0); +} + + +/* + * 'cups_print_pages()' - Send one or more pages to the output file. + */ + +private int /* O - 0 if everything is OK */ +cups_print_pages(gx_device_printer *pdev, /* I - Device info */ + FILE *fp, /* I - Output file */ + int num_copies) /* I - Number of copies */ +{ + int copy; /* Copy number */ + int srcbytes; /* Byte width of scanline */ + int x, y; /* Current position in image */ + unsigned char *src, /* Scanline data */ + *dst; /* Bitmap data */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_print_pages(%08x, %08x, %d)\n", pdev, fp, + num_copies); +#endif /* DEBUG */ + + /* + * Figure out the number of bytes per line... + */ + + switch (cups->header.cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerPixel * + cups->header.cupsWidth + 7) / 8; + break; + + case CUPS_ORDER_BANDED : + cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerPixel * + cups->header.cupsWidth + 7) / 8 * + cups->color_info.num_components; + break; + + case CUPS_ORDER_PLANAR : + cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerPixel * + cups->header.cupsWidth + 7) / 8; + break; + } + + /* + * Compute the width of a scanline and allocate input/output buffers... + */ + + srcbytes = gdev_prn_raster(pdev); + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d, cupsWidth = %d, cupsBytesPerLine = %d, srcbytes = %d\n", + cups->header.cupsBitsPerPixel, cups->header.cupsWidth, + cups->header.cupsBytesPerLine, srcbytes); +#endif /* DEBUG */ + + src = (unsigned char *)gs_malloc(srcbytes, 1, "cups_print_pages"); + + if (src == NULL) /* can't allocate input buffer */ + return_error(gs_error_VMerror); + + if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED) + { + /* + * Need an output buffer, too... + */ + + dst = (unsigned char *)gs_malloc(cups->header.cupsBytesPerLine, 1, + "cups_print_pages"); + + if (dst == NULL) /* can't allocate working area */ + return_error(gs_error_VMerror); + } + else + dst = NULL; + + /* + * See if the stream has been initialized yet... + */ + + if (cups->stream == NULL) + { + if (fp == NULL) + cups->stream = cupsRasterOpen(1, CUPS_RASTER_WRITE); + else + cups->stream = cupsRasterOpen(fileno(fp), CUPS_RASTER_WRITE); + + if (cups->stream == NULL) + { + perror("ERROR: Unable to open raster stream - "); + gs_exit(0); + } + } + + /* + * Output a page of graphics... + */ + + if (num_copies < 1) + num_copies = 1; + + if (cups->ppd != NULL && !cups->ppd->manual_copies) + { + cups->header.NumCopies = num_copies; + num_copies = 1; + } + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cupsWidth = %d, cupsHeight = %d, cupsBytesPerLine = %d\n", + cups->header.cupsWidth, cups->header.cupsHeight, + cups->header.cupsBytesPerLine); +#endif /* DEBUG */ + + for (copy = num_copies; copy > 0; copy --) + { + cupsRasterWriteHeader(cups->stream, &(cups->header)); + + if (pdev->color_info.num_components == 1) + cups_print_chunked(pdev, src); + else + switch (cups->header.cupsColorOrder) + { + case CUPS_ORDER_CHUNKED : + cups_print_chunked(pdev, src); + break; + case CUPS_ORDER_BANDED : + cups_print_banded(pdev, src, dst, srcbytes); + break; + case CUPS_ORDER_PLANAR : + cups_print_planar(pdev, src, dst, srcbytes); + break; + } + } + + /* + * Free temporary storage and return... + */ + + gs_free((char *)src, srcbytes, 1, "cups_print_pages"); + if (dst) + gs_free((char *)dst, cups->header.cupsBytesPerLine, 1, "cups_print_pages"); + + cups->page ++; + fprintf(stderr, "INFO: Processing page %d...\n", cups->page); + + return (0); +} + + +/* + * 'cups_put_params()' - Set pagedevice parameters. + */ + +private int /* O - Error status */ +cups_put_params(gx_device *pdev, /* I - Device info */ + gs_param_list *plist) /* I - Parameter list */ +{ + int i; /* Looping var */ + float margins[4]; /* Physical margins of print */ + ppd_size_t *size; /* Page size */ + int olddepth; /* Old depth value */ + int code; /* Error code */ + int intval; /* Integer value */ + bool boolval; /* Boolean value */ + float floatval; /* Floating point value */ + gs_param_string stringval; /* String value */ + gs_param_float_array arrayval; /* Float array value */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_put_params(%08x, %08x)\n", pdev, plist); +#endif /* DEBUG */ + + /* + * Process other options for CUPS... + */ + +#define stringoption(name, sname) \ + if ((code = param_read_string(plist, sname, &stringval)) < 0) \ + { \ + param_signal_error(plist, sname, code); \ + return (code); \ + } \ + else if (code == 0) \ + { \ + strncpy(cups->header.name, (const char *)stringval.data, \ + stringval.size); \ + cups->header.name[stringval.size] = '\0'; \ + } + +#define intoption(name, sname, type) \ + if ((code = param_read_int(plist, sname, &intval)) < 0) \ + { \ + param_signal_error(plist, sname, code); \ + return (code); \ + } \ + else if (code == 0) \ + cups->header.name = (type)intval; + +#define floatoption(name, sname) \ + if ((code = param_read_float(plist, sname, &floatval)) < 0) \ + { \ + param_signal_error(plist, sname, code); \ + return (code); \ + } \ + else if (code == 0) \ + cups->header.name = (unsigned)floatval; + +#define booloption(name, sname) \ + if ((code = param_read_bool(plist, sname, &boolval)) < 0) \ + { \ + if ((code = param_read_null(plist, sname)) < 0) \ + { \ + param_signal_error(plist, sname, code); \ + return (code); \ + } \ + if (code == 0) \ + cups->header.name = CUPS_FALSE; \ + } \ + else if (code == 0) \ + cups->header.name = (cups_bool_t)boolval; + +#define arrayoption(name, sname, count) \ + if ((code = param_read_float_array(plist, sname, &arrayval)) < 0) \ + { \ + if ((code = param_read_null(plist, sname)) < 0) \ + { \ + param_signal_error(plist, sname, code); \ + return (code); \ + } \ + if (code == 0) \ + for (i = 0; i < count; i ++) \ + cups->header.name[i] = 0; \ + } \ + else if (code == 0) \ + { \ + for (i = 0; i < count; i ++) \ + cups->header.name[i] = (unsigned)arrayval.data[i]; \ + } + + stringoption(MediaClass, "MediaClass") + stringoption(MediaColor, "MediaColor") + stringoption(MediaType, "MediaType") + stringoption(OutputType, "OutputType") + floatoption(AdvanceDistance, "AdvanceDistance") + intoption(AdvanceMedia, "AdvanceMedia", cups_adv_t) + booloption(Collate, "Collate") + intoption(CutMedia, "CutMedia", cups_cut_t) + booloption(Duplex, "Duplex") + arrayoption(ImagingBoundingBox, "ImagingBoundingBox", 4) + booloption(InsertSheet, "InsertSheet") + intoption(Jog, "Jog", cups_jog_t) + intoption(LeadingEdge, "LeadingEdge", cups_edge_t) + arrayoption(Margins, "Margins", 2) + booloption(ManualFeed, "ManualFeed") + intoption(MediaPosition, "cupsMediaPosition", unsigned) + floatoption(MediaWeight, "MediaWeight") + booloption(MirrorPrint, "MirrorPrint") + booloption(NegativePrint, "NegativePrint") + intoption(NumCopies, "NumCopies", unsigned) + intoption(Orientation, "Orientation", cups_orient_t) + booloption(OutputFaceUp, "OutputFaceUp") + booloption(Separations, "Separations") + booloption(TraySwitch, "TraySwitch") + booloption(Tumble, "Tumble") + intoption(cupsWidth, "cupsWidth", unsigned) + intoption(cupsHeight, "cupsHeight", unsigned) + intoption(cupsMediaType, "cupsMediaType", unsigned) + intoption(cupsBitsPerColor, "cupsBitsPerColor", unsigned) + intoption(cupsBitsPerPixel, "cupsBitsPerPixel", unsigned) + intoption(cupsBytesPerLine, "cupsBytesPerLine", unsigned) + intoption(cupsColorOrder, "cupsColorOrder", cups_order_t) + intoption(cupsColorSpace, "cupsColorSpace", cups_cspace_t) + intoption(cupsCompression, "cupsCompression", unsigned) + intoption(cupsRowCount, "cupsRowCount", unsigned) + intoption(cupsRowFeed, "cupsRowFeed", unsigned) + intoption(cupsRowStep, "cupsRowStep", unsigned) + + /* + * Then process standard page device options... + */ + + if ((code = gdev_prn_put_params(pdev, plist)) < 0) + return (code); + + cups->header.HWResolution[0] = pdev->HWResolution[0]; + cups->header.HWResolution[1] = pdev->HWResolution[1]; + + cups->header.PageSize[0] = pdev->MediaSize[0]; + cups->header.PageSize[1] = pdev->MediaSize[1]; + + /* + * Check for a change in color depth... + */ + + olddepth = pdev->color_info.depth; + cups_set_color_info(pdev); + + if (olddepth != pdev->color_info.depth && pdev->is_open) + gs_closedevice(pdev); + + /* + * Compute the page margins... + */ + + if (cups->ppd != NULL) + { + /* + * Set the margins from the PPD file... + */ + + for (i = cups->ppd->num_sizes, size = cups->ppd->sizes; + i > 0; + i --, size ++) + if (size->width == cups->header.PageSize[0] && + size->length == cups->header.PageSize[1]) + break; + + if (i == 0) + { + /* + * Pull margins from custom page size (0 or whatever is defined + * by the PPD file... + */ + + margins[0] = cups->ppd->custom_margins[0] / 72.0; + margins[1] = cups->ppd->custom_margins[1] / 72.0; + margins[2] = cups->ppd->custom_margins[2] / 72.0; + margins[3] = cups->ppd->custom_margins[3] / 72.0; + } + else + { + /* + * Pull the margins from the size entry; since the margins are not + * like the bounding box we have to adjust the top and right values + * accordingly. + */ + + margins[0] = size->left / 72.0; + margins[1] = size->bottom / 72.0; + margins[2] = (size->width - size->right) / 72.0; + margins[3] = (size->length - size->top) / 72.0; + } + } + else + { + /* + * Set default margins of 0.0... + */ + + memset(margins, 0, sizeof(margins)); + } + +#ifdef DEBUG + fprintf(stderr, "DEBUG: ppd = %08x\n", cups->ppd); + fprintf(stderr, "DEBUG: MediaSize = [ %.3f %.3f ]\n", + pdev->MediaSize[0], pdev->MediaSize[1]); + fprintf(stderr, "DEBUG: margins = [ %.3f %.3f %.3f %.3f ]\n", + margins[0], margins[1], margins[2], margins[3]); + fprintf(stderr, "DEBUG: HWResolution = [ %.3f %.3f ]\n", + pdev->HWResolution[0], pdev->HWResolution[1]); + fprintf(stderr, "DEBUG: width = %d, height = %d\n", + pdev->width, pdev->height); + fprintf(stderr, "DEBUG: HWMargins = [ %.3f %.3f %.3f %.3f ]\n", + pdev->HWMargins[0], pdev->HWMargins[1], + pdev->HWMargins[2], pdev->HWMargins[3]); +#endif /* DEBUG */ + + /* + * Set the margins and update the bitmap size... + */ + + gx_device_set_margins(pdev, margins, false); + + if ((code = gdev_prn_put_params(pdev, plist)) < 0) + return (code); + + return (0); +} + + +/* + * 'cups_set_color_info()' - Set the color information structure based on + * the required output. + */ + +private void +cups_set_color_info(gx_device *pdev) /* I - Device info */ +{ + int i, j, k; /* Looping vars */ + float d, g; /* Density and gamma correction */ + char resolution[41]; /* Resolution string */ + ppd_profile_t *profile; /* Color profile information */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG: cups_set_color_info(%08x)\n", pdev); +#endif /* DEBUG */ + + switch (cups->header.cupsColorSpace) + { + default : + case CUPS_CSPACE_W : + case CUPS_CSPACE_K : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor; + cups->color_info.depth = cups->header.cupsBitsPerPixel; + cups->color_info.num_components = 1; + break; + + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + case CUPS_CSPACE_RGB : + if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED) + cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor; + else if (cups->header.cupsBitsPerColor < 8) + cups->header.cupsBitsPerPixel = 4 * cups->header.cupsBitsPerColor; + else + cups->header.cupsBitsPerPixel = 3 * cups->header.cupsBitsPerColor; + + if (cups->header.cupsBitsPerColor < 8) + cups->color_info.depth = 4 * cups->header.cupsBitsPerColor; + else + cups->color_info.depth = 3 * cups->header.cupsBitsPerColor; + + cups->color_info.num_components = 3; + break; + + case CUPS_CSPACE_KCMYcm : + if (cups->header.cupsBitsPerColor == 1) + { + cups->header.cupsBitsPerPixel = 8; + cups->color_info.depth = 4; + cups->color_info.num_components = 4; + break; + } + + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED) + cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor; + else + cups->header.cupsBitsPerPixel = 4 * cups->header.cupsBitsPerColor; + + cups->color_info.depth = 4 * cups->header.cupsBitsPerColor; + cups->color_info.num_components = 4; + break; + } + + if (cups->color_info.num_components > 1) + { + cups->color_info.max_gray = (1 << cups->header.cupsBitsPerColor) - 1; + cups->color_info.max_color = (1 << cups->header.cupsBitsPerColor) - 1; + cups->color_info.dither_grays = (1 << cups->header.cupsBitsPerColor); + cups->color_info.dither_colors = (1 << cups->header.cupsBitsPerColor); + } + else + { + cups->color_info.max_gray = (1 << cups->header.cupsBitsPerColor) - 1; + cups->color_info.max_color = 0; + cups->color_info.dither_grays = (1 << cups->header.cupsBitsPerColor); + cups->color_info.dither_colors = 0; + } + + /* + * Compute the lookup tables... + */ + + for (i = 0; i <= gx_max_color_value; i ++) + lut_rgb_color[i] = cups->color_info.max_gray * i / gx_max_color_value; + + for (i = 0; i < cups->color_info.dither_grays; i ++) + lut_color_rgb[i] = gx_max_color_value * i / cups->color_info.max_gray; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: num_components = %d, depth = %d\n", + cups->color_info.num_components, cups->color_info.depth); + fprintf(stderr, "DEBUG: cupsColorSpace = %d, cupsColorOrder = %d\n", + cups->header.cupsColorSpace, cups->header.cupsColorOrder); + fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d, cupsBitsPerColor = %d\n", + cups->header.cupsBitsPerPixel, cups->header.cupsBitsPerColor); + fprintf(stderr, "DEBUG: max_gray = %d, dither_grays = %d\n", + cups->color_info.max_gray, cups->color_info.dither_grays); + fprintf(stderr, "DEBUG: max_color = %d, dither_colors = %d\n", + cups->color_info.max_color, cups->color_info.dither_colors); +#endif /* DEBUG */ + + /* + * Set the color profile as needed... + */ + + cupsHaveProfile = 0; + + if (cups->ppd != NULL && cups->header.cupsBitsPerColor == 8) + { + /* + * Find the appropriate color profile... + */ + + if (pdev->HWResolution[0] != pdev->HWResolution[1]) + sprintf(resolution, "%.0fx%.0fdpi", pdev->HWResolution[0], + pdev->HWResolution[1]); + else + sprintf(resolution, "%.0fdpi", pdev->HWResolution[0]); + + for (i = 0, profile = cups->ppd->profiles; + i < cups->ppd->num_profiles; + i ++, profile ++) + if ((strcmp(profile->resolution, resolution) == 0 || + profile->resolution[0] == '-') && + (strcmp(profile->media_type, cups->header.MediaType) == 0 || + profile->media_type[0] == '-')) + break; + + /* + * If we found a color profile, use it! + */ + + if (i < cups->ppd->num_profiles) + { +#ifdef DEBUG + fputs("DEBUG: Using color profile!\n", stderr); +#endif /* DEBUG */ + + cupsHaveProfile = 1; + + for (i = 0; i < 3; i ++) + for (j = 0; j < 3; j ++) + for (k = 0; k <= gx_max_color_value; k ++) + { + cupsMatrix[i][j][k] = (int)((float)k * profile->matrix[i][j] + 0.5); + +#ifdef DEBUG + if ((k & 4095) == 0) + fprintf(stderr, "DEBUG: cupsMatrix[%d][%d][%d] = %d\n", + i, j, k, cupsMatrix[i][j][k]); +#endif /* DEBUG */ + } + + d = profile->density; + g = profile->gamma; + + for (k = 0; k <= gx_max_color_value; k ++) + { + cupsDensity[k] = (int)((float)gx_max_color_value * d * + pow((float)k / (float)gx_max_color_value, g) + + 0.5); +#ifdef DEBUG + if ((k & 4095) == 0) + fprintf(stderr, "DEBUG: cupsDensity[%d] = %d\n", k, cupsDensity[k]); +#endif /* DEBUG */ + } + } + } +} + + +/* + * 'cups_sync_output()' - Keep the user informed of our status... + */ + +private int /* O - Error status */ +cups_sync_output(gx_device *pdev) /* I - Device info */ +{ + fprintf(stderr, "INFO: Processing page %d...\n", cups->page); + + return (0); +} + + +/* + * 'cups_print_chunked()' - Print a page of chunked pixels. + */ + +static void +cups_print_chunked(gx_device_printer *pdev, /* I - Printer device */ + unsigned char *src) /* I - Scanline buffer */ +{ + int y; /* Looping var */ + unsigned char *srcptr; /* Pointer to data */ + + + /* + * Loop through the page bitmap and write chunked pixels (the format + * is identical to GhostScript's... + */ + + for (y = 0; y < cups->height; y ++) + { + /* + * Grab the scanline data... + */ + + if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0) + { + fprintf(stderr, "ERROR: Unable to get scanline %d!\n", y); + gs_exit(1); + } + + /* + * Write the scanline data to the raster stream... + */ + + cupsRasterWritePixels(cups->stream, srcptr, cups->header.cupsBytesPerLine); + } +} + + +/* + * 'cups_print_banded()' - Print a page of banded pixels. + */ + +static void +cups_print_banded(gx_device_printer *pdev, /* I - Printer device */ + unsigned char *src, /* I - Scanline buffer */ + unsigned char *dst, /* I - Bitmap buffer */ + int srcbytes) /* I - Number of bytes in src */ +{ + int x; /* Looping var */ + int y; /* Looping var */ + int bandbytes; /* Bytes per band */ + unsigned char bit; /* Current bit */ + unsigned char temp; /* Temporary variable */ + unsigned char *srcptr; /* Pointer to data */ + unsigned char *cptr, *mptr, *yptr, *kptr; /* Pointer to components */ + unsigned char *lcptr, *lmptr; /* ... */ + + + /* + * Loop through the page bitmap and write banded pixels... We have + * to separate each chunked color as needed... + */ + + bandbytes = cups->header.cupsBytesPerLine / pdev->color_info.num_components; + + for (y = 0; y < cups->height; y ++) + { + /* + * Grab the scanline data... + */ + + if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0) + { + fprintf(stderr, "ERROR: Unable to get scanline %d!\n", y); + gs_exit(1); + } + + /* + * Separate the chunked colors into their components... + */ + + if (srcptr[0] == 0 && memcmp(srcptr, srcptr + 1, srcbytes - 1) == 0) + memset(dst, 0, cups->header.cupsBytesPerLine); + else + switch (cups->header.cupsBitsPerColor) + { + case 1 : + memset(dst, 0, cups->header.cupsBytesPerLine); + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, bit = 128; + x > 0; + x --, srcptr ++) + { + if (*srcptr & 0x40) + *cptr |= bit; + if (*srcptr & 0x20) + *mptr |= bit; + if (*srcptr & 0x10) + *yptr |= bit; + + bit >>= 1; + x --; + if (x == 0) + break; + + if (*srcptr & 0x4) + *cptr |= bit; + if (*srcptr & 0x2) + *mptr |= bit; + if (*srcptr & 0x1) + *yptr |= bit; + + if (bit > 1) + bit >>= 1; + else + { + cptr ++; + mptr ++; + yptr ++; + bit = 128; + } + } + break; + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, kptr = yptr + bandbytes, + bit = 128; + x > 0; + x --, srcptr ++) + { + if (*srcptr & 0x80) + *cptr |= bit; + if (*srcptr & 0x40) + *mptr |= bit; + if (*srcptr & 0x20) + *yptr |= bit; + if (*srcptr & 0x10) + *kptr |= bit; + + bit >>= 1; + x --; + if (x == 0) + break; + + if (*srcptr & 0x8) + *cptr |= bit; + if (*srcptr & 0x4) + *mptr |= bit; + if (*srcptr & 0x2) + *yptr |= bit; + if (*srcptr & 0x1) + *kptr |= bit; + + if (bit > 1) + bit >>= 1; + else + { + cptr ++; + mptr ++; + yptr ++; + kptr ++; + bit = 128; + } + } + break; + case CUPS_CSPACE_KCMYcm : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, kptr = yptr + bandbytes, + lcptr = kptr + bandbytes, lmptr = lcptr + bandbytes, + bit = 128; + x > 0; + x --, srcptr ++) + { + if (*srcptr & 0x20) + *cptr |= bit; + if (*srcptr & 0x10) + *mptr |= bit; + if (*srcptr & 0x08) + *yptr |= bit; + if (*srcptr & 0x04) + *kptr |= bit; + if (*srcptr & 0x02) + *lcptr |= bit; + if (*srcptr & 0x01) + *lmptr |= bit; + + if (bit > 1) + bit >>= 1; + else + { + cptr ++; + mptr ++; + yptr ++; + kptr ++; + lcptr ++; + lmptr ++; + bit = 128; + } + } + break; + } + break; + + case 2 : + memset(dst, 0, cups->header.cupsBytesPerLine); + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, bit = 0xc0; + x > 0; + x --, srcptr ++) + switch (bit) + { + case 0xc0 : + if (temp = *srcptr & 0x30) + *cptr |= temp << 2; + if (temp = *srcptr & 0x0c) + *mptr |= temp << 4; + if (temp = *srcptr & 0x03) + *yptr |= temp << 6; + + bit = 0x30; + break; + case 0x30 : + if (temp = *srcptr & 0x30) + *cptr |= temp; + if (temp = *srcptr & 0x0c) + *mptr |= temp << 2; + if (temp = *srcptr & 0x03) + *yptr |= temp << 4; + + bit = 0x0c; + break; + case 0x0c : + if (temp = *srcptr & 0x30) + *cptr |= temp >> 2; + if (temp = *srcptr & 0x0c) + *mptr |= temp; + if (temp = *srcptr & 0x03) + *yptr |= temp << 2; + + bit = 0x03; + break; + case 0x03 : + if (temp = *srcptr & 0x30) + *cptr |= temp >> 4; + if (temp = *srcptr & 0x0c) + *mptr |= temp >> 2; + if (temp = *srcptr & 0x03) + *yptr |= temp; + + bit = 0xc0; + cptr ++; + mptr ++; + yptr ++; + break; + } + break; + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, kptr = yptr + bandbytes, + bit = 0xc0; + x > 0; + x --, srcptr ++) + switch (bit) + { + case 0xc0 : + if (temp = *srcptr & 0xc0) + *cptr |= temp; + if (temp = *srcptr & 0x30) + *mptr |= temp << 2; + if (temp = *srcptr & 0x0c) + *yptr |= temp << 4; + if (temp = *srcptr & 0x03) + *kptr |= temp << 6; + + bit = 0x30; + break; + case 0x30 : + if (temp = *srcptr & 0xc0) + *cptr |= temp >> 2; + if (temp = *srcptr & 0x30) + *mptr |= temp; + if (temp = *srcptr & 0x0c) + *yptr |= temp << 2; + if (temp = *srcptr & 0x03) + *kptr |= temp << 4; + + bit = 0x0c; + break; + case 0x0c : + if (temp = *srcptr & 0xc0) + *cptr |= temp >> 4; + if (temp = *srcptr & 0x30) + *mptr |= temp >> 2; + if (temp = *srcptr & 0x0c) + *yptr |= temp; + if (temp = *srcptr & 0x03) + *kptr |= temp << 2; + + bit = 0x03; + break; + case 0x03 : + if (temp = *srcptr & 0xc0) + *cptr |= temp >> 6; + if (temp = *srcptr & 0x30) + *mptr |= temp >> 4; + if (temp = *srcptr & 0x0c) + *yptr |= temp >> 2; + if (temp = *srcptr & 0x03) + *kptr |= temp; + + bit = 0xc0; + cptr ++; + mptr ++; + yptr ++; + kptr ++; + break; + } + break; + } + break; + + case 4 : + memset(dst, 0, cups->header.cupsBytesPerLine); + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, bit = 0xf0; + x > 0; + x --, srcptr += 2) + switch (bit) + { + case 0xf0 : + if (temp = srcptr[0] & 0x0f) + *cptr |= temp << 4; + if (temp = srcptr[1] & 0xf0) + *mptr |= temp; + if (temp = srcptr[1] & 0x0f) + *yptr |= temp << 4; + + bit = 0x0f; + break; + case 0x0f : + if (temp = srcptr[0] & 0x0f) + *cptr |= temp; + if (temp = srcptr[1] & 0xf0) + *mptr |= temp >> 4; + if (temp = srcptr[1] & 0x0f) + *yptr |= temp; + + bit = 0xf0; + cptr ++; + mptr ++; + yptr ++; + kptr ++; + break; + } + break; + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_KCMYcm : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, kptr = yptr + bandbytes, + bit = 0xf0; + x > 0; + x --, srcptr += 2) + switch (bit) + { + case 0xf0 : + if (temp = srcptr[0] & 0xf0) + *cptr |= temp; + if (temp = srcptr[0] & 0x0f) + *mptr |= temp << 4; + if (temp = srcptr[1] & 0xf0) + *yptr |= temp; + if (temp = srcptr[1] & 0x0f) + *kptr |= temp << 4; + + bit = 0x0f; + break; + case 0x0f : + if (temp = srcptr[0] & 0xf0) + *cptr |= temp >> 4; + if (temp = srcptr[0] & 0x0f) + *mptr |= temp; + if (temp = srcptr[1] & 0xf0) + *yptr |= temp >> 4; + if (temp = srcptr[1] & 0x0f) + *kptr |= temp; + + bit = 0xf0; + cptr ++; + mptr ++; + yptr ++; + kptr ++; + break; + } + break; + } + break; + + case 8 : + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes; + x > 0; + x --) + { + *cptr++ = *srcptr++; + *mptr++ = *srcptr++; + *yptr++ = *srcptr++; + } + break; + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_KCMYcm : + for (x = cups->width, cptr = dst, mptr = cptr + bandbytes, + yptr = mptr + bandbytes, kptr = yptr + bandbytes; + x > 0; + x --) + { + *cptr++ = *srcptr++; + *mptr++ = *srcptr++; + *yptr++ = *srcptr++; + *kptr++ = *srcptr++; + } + break; + } + break; + } + + /* + * Write the bitmap data to the raster stream... + */ + + cupsRasterWritePixels(cups->stream, dst, cups->header.cupsBytesPerLine); + } +} + + +/* + * 'cups_print_planar()' - Print a page of planar pixels. + */ + +static void +cups_print_planar(gx_device_printer *pdev, /* I - Printer device */ + unsigned char *src, /* I - Scanline buffer */ + unsigned char *dst, /* I - Bitmap buffer */ + int srcbytes) /* I - Number of bytes in src */ +{ + int x; /* Looping var */ + int y; /* Looping var */ + int z; /* Looping var */ + unsigned char srcbit; /* Current source bit */ + unsigned char dstbit; /* Current destination bit */ + unsigned char temp; /* Temporary variable */ + unsigned char *srcptr; /* Pointer to data */ + unsigned char *dstptr; /* Pointer to bitmap */ + + + /* + * Loop through the page bitmap and write planar pixels... We have + * to separate each chunked color as needed... + */ + + for (z = 0; z < pdev->color_info.num_components; z ++) + for (y = 0; y < cups->height; y ++) + { + /* + * Grab the scanline data... + */ + + if (gdev_prn_get_bits((gx_device_printer *)pdev, y, src, &srcptr) < 0) + { + fprintf(stderr, "ERROR: Unable to get scanline %d!\n", y); + gs_exit(1); + } + + /* + * Pull the individual color planes out of the pixels... + */ + + if (srcptr[0] == 0 && memcmp(srcptr, srcptr + 1, srcbytes - 1) == 0) + memset(dst, 0, cups->header.cupsBytesPerLine); + else + switch (cups->header.cupsBitsPerColor) + { + case 1 : + memset(dst, 0, cups->header.cupsBytesPerLine); + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + for (dstptr = dst, x = cups->width, srcbit = 64 >> z, + dstbit = 128; + x > 0; + x --) + { + if (*srcptr & srcbit) + *dstptr |= dstbit; + + if (srcbit >= 16) + srcbit >>= 4; + else + { + srcbit = 64 >> z; + srcptr ++; + } + + if (dstbit > 1) + dstbit >>= 1; + else + { + dstbit = 128; + dstptr ++; + } + } + break; + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + for (dstptr = dst, x = cups->width, srcbit = 128 >> z, + dstbit = 128; + x > 0; + x --) + { + if (*srcptr & srcbit) + *dstptr |= dstbit; + + if (srcbit >= 16) + srcbit >>= 4; + else + { + srcbit = 128 >> z; + srcptr ++; + } + + if (dstbit > 1) + dstbit >>= 1; + else + { + dstbit = 128; + dstptr ++; + } + } + break; + case CUPS_CSPACE_KCMYcm : + for (dstptr = dst, x = cups->width, srcbit = 32 >> z, + dstbit = 128; + x > 0; + x --, srcptr ++) + { + if (*srcptr & srcbit) + *dstptr |= dstbit; + + if (dstbit > 1) + dstbit >>= 1; + else + { + dstbit = 128; + dstptr ++; + } + } + break; + } + break; + + case 2 : + memset(dst, 0, cups->header.cupsBytesPerLine); + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + for (dstptr = dst, x = cups->width, srcbit = 48 >> (z * 2), + dstbit = 0xc0; + x > 0; + x --, srcptr ++) + { + if (temp = *srcptr & srcbit) + { + if (srcbit == dstbit) + *dstptr |= temp; + else + { + switch (srcbit) + { + case 0x30 : + temp >>= 4; + break; + case 0x0c : + temp >>= 2; + break; + } + + switch (dstbit) + { + case 0xc0 : + *dstptr |= temp << 6; + break; + case 0x30 : + *dstptr |= temp << 4; + break; + case 0x0c : + *dstptr |= temp << 2; + break; + case 0x03 : + *dstptr |= temp; + break; + } + } + } + + if (dstbit > 0x03) + dstbit >>= 2; + else + { + dstbit = 0xc0; + dstptr ++; + } + } + break; + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_KCMYcm : + for (dstptr = dst, x = cups->width, srcbit = 192 >> (z * 2), + dstbit = 0xc0; + x > 0; + x --, srcptr ++) + { + if (temp = *srcptr & srcbit) + { + if (srcbit == dstbit) + *dstptr |= temp; + else + { + switch (srcbit) + { + case 0xc0 : + temp >>= 6; + break; + case 0x30 : + temp >>= 4; + break; + case 0x0c : + temp >>= 2; + break; + } + + switch (dstbit) + { + case 0xc0 : + *dstptr |= temp << 6; + break; + case 0x30 : + *dstptr |= temp << 4; + break; + case 0x0c : + *dstptr |= temp << 2; + break; + case 0x03 : + *dstptr |= temp; + break; + } + } + } + + if (dstbit > 0x03) + dstbit >>= 2; + else + { + dstbit = 0xc0; + dstptr ++; + } + } + break; + } + break; + + case 4 : + memset(dst, 0, cups->header.cupsBytesPerLine); + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + if (z > 0) + srcptr ++; + + if (z == 1) + srcbit = 0xf0; + else + srcbit = 0x0f; + + for (dstptr = dst, x = cups->width, dstbit = 0xf0; + x > 0; + x --, srcptr += 2) + { + if (temp = *srcptr & srcbit) + { + if (srcbit == dstbit) + *dstptr |= temp; + else + { + if (srcbit == 0xf0) + temp >>= 4; + + if (dstbit == 0xf0) + *dstptr |= temp << 4; + else + *dstptr |= temp; + } + } + + if (dstbit == 0xf0) + dstbit = 0x0f; + else + { + dstbit = 0xf0; + dstptr ++; + } + } + break; + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_KCMYcm : + if (z > 1) + srcptr ++; + + if (z & 1) + srcbit = 0x0f; + else + srcbit = 0xf0; + + for (dstptr = dst, x = cups->width, dstbit = 0xf0; + x > 0; + x --, srcptr += 2) + { + if (temp = *srcptr & srcbit) + { + if (srcbit == dstbit) + *dstptr |= temp; + else + { + if (srcbit == 0xf0) + temp >>= 4; + + if (dstbit == 0xf0) + *dstptr |= temp << 4; + else + *dstptr |= temp; + } + } + + if (dstbit == 0xf0) + dstbit = 0x0f; + else + { + dstbit = 0xf0; + dstptr ++; + } + } + break; + } + break; + + case 8 : + for (srcptr += z, dstptr = dst, x = cups->header.cupsBytesPerLine; + x > 0; + srcptr += pdev->color_info.num_components, x --) + *dstptr++ = *srcptr; + break; + } + + /* + * Write the bitmap data to the raster stream... + */ + + cupsRasterWritePixels(cups->stream, dst, cups->header.cupsBytesPerLine); + } +} + + +/* + * End of "$Id$". + */ diff --git a/pstoraster/gdevddrw.c b/pstoraster/gdevddrw.c new file mode 100644 index 0000000000..85536350aa --- /dev/null +++ b/pstoraster/gdevddrw.c @@ -0,0 +1,470 @@ +/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevddrw.c */ +/* Default polygon and image drawing device procedures */ +#include "math_.h" +#include "gx.h" +#include "gpcheck.h" +#include "gserrors.h" +#include "gxfixed.h" +#include "gxmatrix.h" +#include "gxdcolor.h" +#include "gxdevice.h" + +/* ---------------- Polygon and line drawing ---------------- */ + +/* Define the 'remainder' analogue of fixed_mult_quo. */ +private fixed +fixed_mult_rem(fixed a, fixed b, fixed c) +{ double prod = (double)a * b; + return (fixed)(prod - floor(prod / c) * c); +} + +/* + * Fill a trapezoid. Requires: + * {left,right}->start.y <= ybot <= ytop <= {left,right}->end.y. + * Lines where left.x >= right.x will not be drawn. Thanks to Paul Haeberli + * for an early floating point version of this algorithm. + */ +typedef struct trap_line_s { + int di; fixed df; /* dx/dy ratio = di + df/h */ + fixed ldi, ldf; /* increment per scan line = ldi + ldf/h */ + fixed x, xf; /* current value */ + fixed h; +} trap_line; +int +gx_default_fill_trapezoid(gx_device *dev, const gs_fixed_edge *left, + const gs_fixed_edge *right, fixed ybot, fixed ytop, bool swap_axes, + const gx_device_color *pdevc, gs_logical_operation_t lop) +{ const fixed ymin = fixed_pixround(ybot) + fixed_half; + const fixed ymax = fixed_pixround(ytop); + if ( ymin >= ymax ) return 0; /* no scan lines to sample */ + { int iy = fixed2int_var(ymin); + const int iy1 = fixed2int_var(ymax); + trap_line l, r; + int rxl, rxr, ry; + const fixed + x0l = left->start.x, x1l = left->end.x, + x0r = right->start.x, x1r = right->end.x, + dxl = x1l - x0l, dxr = x1r - x0r; + const fixed /* partial pixel offset to first line to sample */ + ysl = ymin - left->start.y, + ysr = ymin - right->start.y; + fixed fxl; + bool fill_direct = color_writes_pure(pdevc, lop); + gx_color_index cindex; + dev_proc_fill_rectangle((*fill_rect)); + int max_rect_height = 1; /* max height to do fill as rectangle */ + int code; + + if_debug2('z', "[z]y=[%d,%d]\n", iy, iy1); + + if ( fill_direct ) + cindex = pdevc->colors.pure, + fill_rect = dev_proc(dev, fill_rectangle); + l.h = left->end.y - left->start.y; + r.h = right->end.y - right->start.y; + l.x = x0l + (fixed_half - fixed_epsilon); + r.x = x0r + (fixed_half - fixed_epsilon); + ry = iy; + +#define fill_trap_rect(x,y,w,h)\ + (fill_direct ?\ + (swap_axes ? (*fill_rect)(dev, y, x, h, w, cindex) :\ + (*fill_rect)(dev, x, y, w, h, cindex)) :\ + swap_axes ? gx_fill_rectangle_device_rop(y, x, h, w, pdevc, dev, lop) :\ + gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop)) + + /* Compute the dx/dy ratios. */ + /* dx# = dx#i + (dx#f / h#). */ +#define compute_dx(tl, d, ys)\ + if ( d >= 0 )\ + { if ( d < tl.h ) tl.di = 0, tl.df = d;\ + else tl.di = (int)(d / tl.h), tl.df = d - tl.di * tl.h,\ + tl.x += ys * tl.di;\ + }\ + else\ + { if ( (tl.df = d + tl.h) >= 0 /* d >= -tl.h */ ) tl.di = -1, tl.x -= ys;\ + else tl.di = (int)-((tl.h - 1 - d) / tl.h), tl.df = d - tl.di * tl.h,\ + tl.x += ys * tl.di;\ + } + + /* Compute the x offsets at the first scan line to sample. */ + /* We need to be careful in computing ys# * dx#f {/,%} h# */ + /* because the multiplication may overflow. We know that */ + /* all the quantities involved are non-negative, and that */ + /* ys# is usually than 1 (as a fixed, of course); this gives us */ + /* a cheap conservative check for overflow in the multiplication. */ +#define ymult_limit (max_fixed / fixed_1) +#define ymult_quo(ys, tl)\ + (ys < fixed_1 && tl.df < ymult_limit ? ys * tl.df / tl.h :\ + fixed_mult_quo(ys, tl.df, tl.h)) + + /* + * It's worth checking for dxl == dxr, since this is the case + * for parallelograms (including stroked lines). + * Also check for left or right vertical edges. + */ + if ( fixed_floor(l.x) == fixed_pixround(x1l) ) + { /* Left edge is vertical, we don't need to increment. */ + l.di = 0, l.df = 0; + fxl = 0; + } + else + { compute_dx(l, dxl, ysl); + fxl = ymult_quo(ysl, l); + l.x += fxl; + } + if ( fixed_floor(r.x) == fixed_pixround(x1r) ) + { /* Right edge is vertical. If both are vertical, */ + /* we have a rectangle. */ + if ( l.di == 0 && l.df == 0 ) + max_rect_height = max_int; + else + r.di = 0, r.df = 0; + } + /* The test for fxl != 0 is required because the right edge */ + /* might cross some pixel centers even if the left edge doesn't. */ + else if ( dxr == dxl && fxl != 0 ) + { if ( l.di == 0 ) + r.di = 0, r.df = l.df; + else /* too hard to do adjustments right */ + compute_dx(r, dxr, ysr); + if ( ysr == ysl && r.h == l.h ) + r.x += fxl; + else + r.x += ymult_quo(ysr, r); + } + else + { compute_dx(r, dxr, ysr); + r.x += ymult_quo(ysr, r); + } + rxl = fixed2int_var(l.x); + rxr = fixed2int_var(r.x); + + /* + * Take a shortcut if we're only sampling a single scan line, + * or if we have a rectangle. + */ + if ( iy1 - iy <= max_rect_height ) + { iy = iy1; + if_debug2('z', "[z]rectangle, x=[%d,%d]\n", rxl, rxr); + goto last; + } + + /* Compute one line's worth of dx/dy. */ + /* dx# * fixed_1 = ld#i + (ld#f / h#). */ +#define compute_ldx(tl, ys)\ + if ( tl.df < ymult_limit )\ + { if ( tl.df == 0 ) /* vertical edge, worth checking for */\ + tl.ldi = int2fixed(tl.di),\ + tl.ldf = 0,\ + tl.xf = -tl.h;\ + else\ + tl.ldi = int2fixed(tl.di) + int2fixed(tl.df) / tl.h,\ + tl.ldf = int2fixed(tl.df) % tl.h,\ + tl.xf = (ys < fixed_1 ? ys * tl.df % tl.h :\ + fixed_mult_rem(ys, tl.df, tl.h)) - tl.h;\ + }\ + else\ + tl.ldi = int2fixed(tl.di) + fixed_mult_quo(fixed_1, tl.df, tl.h),\ + tl.ldf = fixed_mult_rem(fixed_1, tl.df, tl.h),\ + tl.xf = fixed_mult_rem(ys, tl.df, tl.h) - tl.h + compute_ldx(l, ysl); + if ( dxr == dxl && ysr == ysl && r.h == l.h ) + r.ldi = l.ldi, r.ldf = l.ldf, r.xf = l.xf; + else + { compute_ldx(r, ysr); + } +#undef compute_ldx + + while ( ++iy != iy1 ) + { int ixl, ixr; +#define step_line(tl)\ + tl.x += tl.ldi;\ + if ( (tl.xf += tl.ldf) >= 0 ) tl.xf -= tl.h, tl.x++; + step_line(l); + step_line(r); +#undef step_line + ixl = fixed2int_var(l.x); + ixr = fixed2int_var(r.x); + if ( ixl != rxl || ixr != rxr ) + { code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry); + if ( code < 0 ) goto xit; + rxl = ixl, rxr = ixr, ry = iy; + } + } +last: code = fill_trap_rect(rxl, ry, rxr - rxl, iy - ry); +xit: if ( code < 0 && fill_direct ) + return_error(code); + return_if_interrupt(); + return code; + } +} + +/* Fill a parallelogram whose points are p, p+a, p+b, and p+a+b. */ +/* We should swap axes to get best accuracy, but we don't. */ +/* We must be very careful to follow the center-of-pixel rule in all cases. */ +int +gx_default_fill_parallelogram(gx_device *dev, + fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, + const gx_device_color *pdevc, gs_logical_operation_t lop) +{ fixed t; + fixed qx, qy, ym; + dev_proc_fill_trapezoid((*fill_trapezoid)); + gs_fixed_edge left, right; + int code; + + /* Ensure ay >= 0, by >= 0. */ + if ( ay < 0 ) + px += ax, py += ay, ax = -ax, ay = -ay; + if ( by < 0 ) + px += bx, py += by, bx = -bx, by = -by; + qx = px + ax + bx; + /* Make a special fast check for rectangles. */ + if ( (ay | bx) == 0 || (by | ax) == 0 ) + { /* If a point falls exactly on the middle of a pixel, */ + /* we must round it down, not up. */ + int rx = fixed2int_pixround(px); + int ry = fixed2int_pixround(py); + /* Exactly one of (ax,bx) and one of (ay,by) is non-zero. */ + int w = fixed2int_pixround(qx) - rx; + if ( w < 0 ) rx += w, w = -w; + return gx_fill_rectangle_device_rop(rx, ry, w, + fixed2int_pixround(py + ay + by) - ry, + pdevc, dev, lop); + } + /* Not a rectangle. Ensure ax <= bx. */ +#define swap(r, s) (t = r, r = s, s = t) + if ( ax > bx ) + swap(ax, bx), swap(ay, by); + fill_trapezoid = dev_proc(dev, fill_trapezoid); + qy = py + ay + by; + left.start.x = right.start.x = px; + left.start.y = right.start.y = py; + left.end.x = px + ax; + left.end.y = py + ay; + right.end.x = px + bx; + right.end.y = py + by; +#define rounded_same(p1, p2)\ + (fixed_pixround(p1) == fixed_pixround(p2)) + if ( ay < by ) + { if ( !rounded_same(py, left.end.y) ) + { code = (*fill_trapezoid)(dev, &left, &right, py, left.end.y, + false, pdevc, lop); + if ( code < 0 ) + return code; + } + left.start = left.end; + left.end.x = qx, left.end.y = qy; + ym = right.end.y; + if ( !rounded_same(left.start.y, ym) ) + { code = (*fill_trapezoid)(dev, &left, &right, left.start.y, ym, + false, pdevc, lop); + if ( code < 0 ) + return code; + } + right.start = right.end; + right.end.x = qx, right.end.y = qy; + } + else + { if ( !rounded_same(py, right.end.y) ) + { code = (*fill_trapezoid)(dev, &left, &right, py, right.end.y, + false, pdevc, lop); + if ( code < 0 ) + return code; + } + right.start = right.end; + right.end.x = qx, right.end.y = qy; + ym = left.end.y; + if ( !rounded_same(right.start.y, ym) ) + { code = (*fill_trapezoid)(dev, &left, &right, right.start.y, ym, + false, pdevc, lop); + if ( code < 0 ) + return code; + } + left.start = left.end; + left.end.x = qx, left.end.y = qy; + } + if ( !rounded_same(ym, qy) ) + return (*fill_trapezoid)(dev, &left, &right, ym, qy, + false, pdevc, lop); + else + return 0; +#undef rounded_same +#undef swap +} + +/* Fill a triangle whose points are p, p+a, and p+b. */ +/* We should swap axes to get best accuracy, but we don't. */ +int +gx_default_fill_triangle(gx_device *dev, + fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, + const gx_device_color *pdevc, gs_logical_operation_t lop) +{ fixed t; + fixed ym; + dev_proc_fill_trapezoid((*fill_trapezoid)) = + dev_proc(dev, fill_trapezoid); + gs_fixed_edge left, right; + int code; + + /* Ensure ay >= 0, by >= 0. */ + if ( ay < 0 ) + px += ax, py += ay, bx -= ax, by -= ay, ax = -ax, ay = -ay; + if ( by < 0 ) + px += bx, py += by, ax -= bx, ay -= by, bx = -bx, by = -by; + /* Ensure ax <= bx. */ +#define swap(r, s) (t = r, r = s, s = t) + if ( ax > bx ) + swap(ax, bx), swap(ay, by); +#undef swap + left.start.y = right.start.y = py; + /* Make a special check for a flat bottom or top, */ + /* which we can handle with a single call on fill_trapezoid. */ + if ( ay < by ) + { right.end.x = px + bx, right.end.y = py + by; + if ( ay == 0 ) + { if ( ax < 0 ) + left.start.x = px + ax, right.start.x = px; + else + left.start.x = px, right.start.x = px + ax; + left.end.x = right.end.x, left.end.y = right.end.y; + ym = py; + } + else + { left.start.x = right.start.x = px; + left.end.x = px + ax, left.end.y = py + ay; + code = (*fill_trapezoid)(dev, &left, &right, py, left.end.y, + false, pdevc, lop); + if ( code < 0 ) + return code; + left.start = left.end; + left.end = right.end; + ym = left.start.x; + } + } + else if ( by < ay ) + { left.end.x = px + ax, left.end.y = py + by; + if ( by == 0 ) + { if ( bx < 0 ) + left.start.x = px + bx, right.start.x = px; + else + left.start.x = px, right.start.x = px + bx; + right.end.x = left.end.x, right.end.y = left.end.y; + ym = py; + } + else + { left.start.x = right.start.x = px; + right.end.x = px + bx, right.end.y = py + by; + code = (*fill_trapezoid)(dev, &left, &right, py, right.end.y, + false, pdevc, lop); + if ( code < 0 ) + return code; + right.start = right.end; + right.end = left.end; + ym = right.start.x; + } + } + else /* ay == by */ + { left.start.x = right.start.x = px; + left.end.x = px + ax, left.end.y = py + ay; + right.end.x = px + bx, right.end.y = py + by; + ym = py; + } + return (*fill_trapezoid)(dev, &left, &right, ym, right.end.y, + false, pdevc, lop); +} + +/* Draw a one-pixel-wide line. */ +int +gx_default_draw_thin_line(gx_device *dev, + fixed fx0, fixed fy0, fixed fx1, fixed fy1, + const gx_device_color *pdevc, gs_logical_operation_t lop) +{ int ix = fixed2int_var(fx0); + int iy = fixed2int_var(fy0); + int itox = fixed2int_var(fx1); + int itoy = fixed2int_var(fy1); + + return_if_interrupt(); + if ( itoy == iy ) /* horizontal line */ + { return (ix <= itox ? + gx_fill_rectangle_device_rop(ix, iy, itox - ix + 1, 1, + pdevc, dev, lop) : + gx_fill_rectangle_device_rop(itox, iy, ix - itox + 1, 1, + pdevc, dev, lop) + ); + } + if ( itox == ix ) /* vertical line */ + { return (iy <= itoy ? + gx_fill_rectangle_device_rop(ix, iy, 1, itoy - iy + 1, + pdevc, dev, lop) : + gx_fill_rectangle_device_rop(ix, itoy, 1, iy - itoy + 1, + pdevc, dev, lop) + ); + } + if ( color_writes_pure(pdevc, lop) && + (*dev_proc(dev, draw_line))(dev, ix, iy, itox, itoy, + pdevc->colors.pure) >= 0 + ) + return 0; + { fixed h = fy1 - fy0; + fixed w = fx1 - fx0; + fixed tf; + bool swap_axes; + gs_fixed_edge left, right; + +#define fswap(a, b) tf = a, a = b, b = tf + if ( (w < 0 ? -w : w) <= (h < 0 ? -h : h) ) + { if ( h < 0 ) + fswap(fx0, fx1), fswap(fy0, fy1), + h = -h; + right.start.x = (left.start.x = fx0 - fixed_half) + fixed_1; + right.end.x = (left.end.x = fx1 - fixed_half) + fixed_1; + left.start.y = right.start.y = fy0; + left.end.y = right.end.y = fy1; + swap_axes = false; + } + else + { if ( w < 0 ) + fswap(fx0, fx1), fswap(fy0, fy1), + w = -w; + right.start.x = (left.start.x = fy0 - fixed_half) + fixed_1; + right.end.x = (left.end.x = fy1 - fixed_half) + fixed_1; + left.start.y = right.start.y = fx0; + left.end.y = right.end.y = fx1; + swap_axes = true; + } + return (*dev_proc(dev, fill_trapezoid))(dev, &left, &right, + left.start.y, left.end.y, + swap_axes, pdevc, lop); +#undef fswap + } +} + +/* Stub out the obsolete procedure. */ +int +gx_default_draw_line(gx_device *dev, + int x0, int y0, int x1, int y1, gx_color_index color) +{ return -1; +} diff --git a/pstoraster/gdevdflt.c b/pstoraster/gdevdflt.c new file mode 100644 index 0000000000..27bcc9a3b6 --- /dev/null +++ b/pstoraster/gdevdflt.c @@ -0,0 +1,878 @@ +/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevdflt.c */ +/* Default device implementation */ +#include "gx.h" +#include "gpcheck.h" +#include "gserrors.h" +#include "gxdevice.h" +#include "gxdevmem.h" +#include "gxcpath.h" + +/* ---------------- Default device procedures ---------------- */ + +/* Define the default implementations of RasterOp procedures. */ +/* If the RasterOp option is linked in, it initializes these */ +/* to different values. */ +dev_proc_copy_rop((*gx_default_copy_rop_proc)) = gx_no_copy_rop; +dev_proc_copy_rop((*gx_forward_copy_rop_proc)) = gx_no_copy_rop; +dev_proc_strip_copy_rop((*gx_default_strip_copy_rop_proc)) = gx_no_strip_copy_rop; +dev_proc_strip_copy_rop((*gx_forward_strip_copy_rop_proc)) = gx_no_strip_copy_rop; + +/* Fill in NULL procedures in a device procedure record. */ +void +gx_device_fill_in_procs(register gx_device *dev) +{ gx_device_set_procs(dev); + fill_dev_proc(dev, open_device, gx_default_open_device); + fill_dev_proc(dev, get_initial_matrix, gx_default_get_initial_matrix); + fill_dev_proc(dev, sync_output, gx_default_sync_output); + fill_dev_proc(dev, output_page, gx_default_output_page); + fill_dev_proc(dev, close_device, gx_default_close_device); + fill_dev_proc(dev, map_rgb_color, gx_default_map_rgb_color); + fill_dev_proc(dev, map_color_rgb, gx_default_map_color_rgb); + /* NOT fill_rectangle */ + fill_dev_proc(dev, tile_rectangle, gx_default_tile_rectangle); + fill_dev_proc(dev, copy_mono, gx_default_copy_mono); + fill_dev_proc(dev, copy_color, gx_default_copy_color); + fill_dev_proc(dev, draw_line, gx_default_draw_line); + fill_dev_proc(dev, get_bits, gx_default_get_bits); + fill_dev_proc(dev, get_params, gx_default_get_params); + fill_dev_proc(dev, put_params, gx_default_put_params); + fill_dev_proc(dev, map_cmyk_color, gx_default_map_cmyk_color); + fill_dev_proc(dev, get_xfont_procs, gx_default_get_xfont_procs); + fill_dev_proc(dev, get_xfont_device, gx_default_get_xfont_device); + fill_dev_proc(dev, map_rgb_alpha_color, gx_default_map_rgb_alpha_color); + fill_dev_proc(dev, get_page_device, gx_default_get_page_device); + fill_dev_proc(dev, get_alpha_bits, gx_default_get_alpha_bits); + fill_dev_proc(dev, copy_alpha, gx_default_copy_alpha); + fill_dev_proc(dev, get_band, gx_default_get_band); + fill_dev_proc(dev, copy_rop, gx_default_copy_rop_proc); + fill_dev_proc(dev, fill_path, gx_default_fill_path); + fill_dev_proc(dev, stroke_path, gx_default_stroke_path); + fill_dev_proc(dev, fill_mask, gx_default_fill_mask); + fill_dev_proc(dev, fill_trapezoid, gx_default_fill_trapezoid); + fill_dev_proc(dev, fill_parallelogram, gx_default_fill_parallelogram); + fill_dev_proc(dev, fill_triangle, gx_default_fill_triangle); + fill_dev_proc(dev, draw_thin_line, gx_default_draw_thin_line); + fill_dev_proc(dev, begin_image, gx_default_begin_image); + fill_dev_proc(dev, image_data, gx_default_image_data); + fill_dev_proc(dev, end_image, gx_default_end_image); + fill_dev_proc(dev, strip_tile_rectangle, gx_default_strip_tile_rectangle); + fill_dev_proc(dev, strip_copy_rop, gx_default_strip_copy_rop_proc); +} + +int +gx_default_open_device(gx_device *dev) +{ return 0; +} + +/* Get the initial matrix for a device with inverted Y. */ +/* This includes essentially all printers and displays. */ +void +gx_default_get_initial_matrix(gx_device *dev, register gs_matrix *pmat) +{ pmat->xx = dev->HWResolution[0] / 72.0; /* x_pixels_per_inch */ + pmat->xy = 0; + pmat->yx = 0; + pmat->yy = dev->HWResolution[1] / -72.0; /* y_pixels_per_inch */ + /****** tx/y is WRONG for devices with ******/ + /****** arbitrary initial matrix ******/ + pmat->tx = 0; + pmat->ty = dev->height; +} +/* Get the initial matrix for a device with upright Y. */ +/* This includes just a few printers and window systems. */ +void +gx_upright_get_initial_matrix(gx_device *dev, register gs_matrix *pmat) +{ pmat->xx = dev->HWResolution[0] / 72.0; /* x_pixels_per_inch */ + pmat->xy = 0; + pmat->yx = 0; + pmat->yy = dev->HWResolution[1] / 72.0; /* y_pixels_per_inch */ + /****** tx/y is WRONG for devices with ******/ + /****** arbitrary initial matrix ******/ + pmat->tx = 0; + pmat->ty = 0; +} + +int +gx_default_sync_output(gx_device *dev) +{ return 0; +} + +int +gx_default_output_page(gx_device *dev, int num_copies, int flush) +{ return (*dev_proc(dev, sync_output))(dev); +} + +int +gx_default_close_device(gx_device *dev) +{ return 0; +} + +/* By default, implement tile_rectangle using strip_tile_rectangle. */ +int +gx_default_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile, + int x, int y, int w, int h, gx_color_index color0, gx_color_index color1, + int px, int py) +{ gx_strip_bitmap tiles; + *(gx_tile_bitmap *)&tiles = *tile; + tiles.shift = tiles.rep_shift = 0; + return (*dev_proc(dev, strip_tile_rectangle)) + (dev, &tiles, x, y, w, h, color0, color1, px, py); +} + +/* Implement copy_mono by filling lots of small rectangles. */ +/* This is very inefficient, but it works as a default. */ +int +gx_default_copy_mono(gx_device *dev, const byte *data, + int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h, + gx_color_index zero, gx_color_index one) +{ byte invert; + gx_color_index color; + dev_proc_fill_rectangle((*fill)); + const byte *row; + int iy; + + fit_copy(dev, data, dx, raster, id, x, y, w, h); + fill = dev_proc(dev, fill_rectangle); + if ( one != gx_no_color_index ) + { invert = 0; + color = one; + if ( zero != gx_no_color_index ) + { int code = (*fill)(dev, x, y, w, h, zero); + if ( code < 0 ) + return code; + } + } + else + { invert = 0xff; + color = zero; + } + for ( row = data, iy = 0; iy < h; row += raster, iy++ ) + { int ix; + for ( ix = 0; ix < w; ) + { int i0; +#define row_bit(i) ((row[(i) >> 3] ^ invert) & (0x80 >> ((i) & 7))) + while ( ix < w && row_bit(ix + dx) == 0 ) + ix++; + for ( i0 = ix; ix < w && row_bit(ix + dx) != 0; ) + ix++; + if ( ix > i0 ) + { int code = (*fill)(dev, i0 + x, iy + y, ix - i0, 1, color); + if ( code < 0 ) + return code; + } +#undef row_bit + } + } + return 0; +} + +/* Implement copy_color by filling lots of small rectangles. */ +/* This is very inefficient, but it works as a default. */ +int +gx_default_copy_color(gx_device *dev, const byte *data, + int dx, int raster, gx_bitmap_id id, + int x, int y, int w, int h) +{ int depth = dev->color_info.depth; + byte mask; + dev_proc_fill_rectangle((*fill)); + const byte *row; + int iy; + + if ( depth == 1 ) + return (*dev_proc(dev, copy_mono))(dev, data, dx, raster, id, + x, y, w, h, + (gx_color_index)0, (gx_color_index)1); + fit_copy(dev, data, dx, raster, id, x, y, w, h); + fill = dev_proc(dev, fill_rectangle); + mask = (byte)((1 << depth) - 1); + for ( row = data, iy = 0; iy < h; row += raster, ++iy ) + { int ix; + gx_color_index c0 = gx_no_color_index; + const byte *ptr = row + ((dx * depth) >> 3); + int i0; + + for ( i0 = ix = 0; ix < w; ++ix ) + { gx_color_index color; + + if ( depth >= 8 ) + { color = *ptr++; + switch ( depth ) + { + case 32: color = (color << 8) + *ptr++; + case 24: color = (color << 8) + *ptr++; + case 16: color = (color << 8) + *ptr++; + } + } + else + { uint dbit = (-(ix + dx + 1) * depth) & 7; + color = (*ptr >> dbit) & mask; + if ( dbit == 0 ) + ptr++; + } + if ( color != c0 ) + { if ( ix > i0 ) + { int code = (*fill) + (dev, i0 + x, iy + y, ix - i0, 1, c0); + if ( code < 0 ) + return code; + } + c0 = color; + i0 = ix; + } + } + if ( ix > i0 ) + { int code = (*fill)(dev, i0 + x, iy + y, ix - i0, 1, c0); + if ( code < 0 ) + return code; + } + } + return 0; +} + +int +gx_default_get_bits(gx_device *dev, int y, byte *data, byte **actual_data) +{ return_error(gs_error_unknownerror); +} + +gx_xfont_procs * +gx_default_get_xfont_procs(gx_device *dev) +{ return NULL; +} + +gx_device * +gx_default_get_xfont_device(gx_device *dev) +{ return dev; +} + +gx_device * +gx_default_get_page_device(gx_device *dev) +{ return NULL; +} +gx_device * +gx_page_device_get_page_device(gx_device *dev) +{ return dev; +} + +int +gx_default_get_alpha_bits(gx_device *dev, graphics_object_type type) +{ return 1; +} + +int +gx_no_copy_alpha(gx_device *dev, const byte *data, int data_x, + int raster, gx_bitmap_id id, int x, int y, int width, int height, + gx_color_index color, int depth) +{ return_error(gs_error_unknownerror); +} + +int +gx_default_copy_alpha(gx_device *dev, const byte *data, int data_x, + int raster, gx_bitmap_id id, int x, int y, int width, int height, + gx_color_index color, int depth) +{ /* This might be called with depth = 1.... */ + if ( depth == 1 ) + return (*dev_proc(dev, copy_mono))(dev, data, data_x, raster, id, + x, y, width, height, + gx_no_color_index, color); + /* + * Simulate alpha by weighted averaging of RGB values. + * This is very slow, but functionally correct. + */ + { const byte *row; + gs_memory_t *mem = &gs_memory_default; /* dev might not have one */ + int bpp = dev->color_info.depth; + uint in_size = gx_device_raster(dev, false); + byte *lin; + uint out_size; + byte *lout; + int code = 0; + gx_color_value color_rgb[3]; + int ry; + + fit_copy(dev, data, data_x, raster, id, x, y, width, height); + row = data; + out_size = bitmap_raster(width * bpp); + lin = gs_alloc_bytes(mem, in_size, "copy_alpha(lin)"); + lout = gs_alloc_bytes(mem, out_size, "copy_alpha(lout)"); + if ( lin == 0 || lout == 0 ) + { code = gs_note_error(gs_error_VMerror); + goto out; + } + (*dev_proc(dev, map_color_rgb))(dev, color, color_rgb); + for ( ry = y; ry < y + height; row += raster, ++ry ) + { byte *line; + int sx, rx; + declare_line_accum(lout, bpp, x); + + code = (*dev_proc(dev, get_bits))(dev, ry, lin, &line); + if ( code < 0 ) + break; + for ( sx = data_x, rx = x; sx < data_x + width; ++sx, ++rx ) + { gx_color_index previous = gx_no_color_index; + gx_color_index composite; + int alpha2, alpha; + + if ( depth == 2 ) /* map 0 - 3 to 0 - 15 */ + alpha = ((row[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 5; + else + alpha2 = row[sx >> 1], + alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4); +blend: if ( alpha == 15 ) + { /* Just write the new color. */ + composite = color; + } + else + { if ( previous == gx_no_color_index ) + { /* Extract the old color. */ + if ( bpp < 8 ) + { const uint bit = rx * bpp; + const byte *src = line + (bit >> 3); + previous = + (*src >> (8 - (bit + bpp))) & + ((1 << bpp) - 1); + } + else + { const byte *src = line + (rx * (bpp >> 3)); + previous = 0; + switch ( bpp >> 3 ) + { + case 4: + previous += (gx_color_index)*src++ << 24; + case 3: + previous += (gx_color_index)*src++ << 16; + case 2: + previous += (gx_color_index)*src++ << 8; + case 1: + previous += *src++; + } + } + } + if ( alpha == 0 ) + { /* Just write the old color. */ + composite = previous; + } + else + { /* Blend RGB values. */ + gx_color_value rgb[3]; + + (*dev_proc(dev, map_color_rgb))(dev, previous, rgb); +#if arch_ints_are_short +# define b_int long +#else +# define b_int int +#endif +#define make_shade(old, clr, alpha, amax) \ + (old) + (((b_int)(clr) - (b_int)(old)) * (alpha) / (amax)) + rgb[0] = make_shade(rgb[0], color_rgb[0], alpha, 15); + rgb[1] = make_shade(rgb[1], color_rgb[1], alpha, 15); + rgb[2] = make_shade(rgb[2], color_rgb[2], alpha, 15); +#undef b_int +#undef make_shade + composite = + (*dev_proc(dev, map_rgb_color))(dev, rgb[0], + rgb[1], rgb[2]); + if ( composite == gx_no_color_index ) + { /* The device can't represent this color. */ + /* Move the alpha value towards 0 or 1. */ + if ( alpha == 7 ) /* move 1/2 towards 1 */ + ++alpha; + alpha = (alpha & 8) | (alpha >> 1); + goto blend; + } + } + } + line_accum(composite, bpp); + } + line_accum_copy(dev, lout, bpp, x, rx, raster, ry); + } +out: gs_free_object(mem, lout, "copy_alpha(lout)"); + gs_free_object(mem, lin, "copy_alpha(lin)"); + return code; + } +} + +int +gx_default_get_band(gx_device *dev, int y, int *band_start) +{ return 0; +} + +int +gx_no_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_tile_bitmap *texture, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ return_error(gs_error_unknownerror); /* not implemented */ +} +int +gx_default_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_tile_bitmap *texture, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ return (*gx_default_copy_rop_proc) + (dev, sdata, sourcex, sraster, id, scolors, texture, tcolors, + x, y, width, height, phase_x, phase_y, lop); +} + +int +gx_default_fill_mask(gx_device *orig_dev, + const byte *data, int dx, int raster, gx_bitmap_id id, + int x, int y, int w, int h, + const gx_drawing_color *pdcolor, int depth, + gs_logical_operation_t lop, const gx_clip_path *pcpath) +{ gx_device *dev; + gx_device_clip cdev; + gx_color_index colors[2]; + gx_strip_bitmap *tile; + + if ( gx_dc_is_pure(pdcolor) ) + { tile = 0; + colors[0] = gx_no_color_index; + colors[1] = gx_dc_pure_color(pdcolor); + } + else if ( gx_dc_is_binary_halftone(pdcolor) ) + { tile = gx_dc_binary_tile(pdcolor); + colors[0] = gx_dc_binary_color0(pdcolor); + colors[1] = gx_dc_binary_color1(pdcolor); + } + else + return_error(gs_error_unknownerror); /* not implemented */ + if ( pcpath != 0 ) + { gx_make_clip_path_device(&cdev, pcpath); + cdev.target = orig_dev; + dev = (gx_device *)&cdev; + (*dev_proc(dev, open_device))(dev); + } + else + dev = orig_dev; + if ( depth > 1 ) + { /****** CAN'T DO ROP OR HALFTONE WITH ALPHA ******/ + return (*dev_proc(dev, copy_alpha)) + (dev, data, dx, raster, id, x, y, w, h, colors[1], depth); + } + if ( lop != lop_default ) + { gx_color_index scolors[2]; + + scolors[0] = 1; + scolors[1] = 0; + return (*dev_proc(dev, strip_copy_rop)) + (dev, data, dx, raster, id, scolors, tile, colors, + x, y, w, h, + gx_dc_phase(pdcolor).x, gx_dc_phase(pdcolor).y, lop); + } + if ( tile == 0 ) + { return (*dev_proc(dev, copy_mono)) + (dev, data, dx, raster, id, x, y, w, h, + gx_no_color_index, colors[1]); + } + /* + * Use the same approach as the default copy_mono (above). We + * should really clip to the intersection of the bounding boxes of + * the device and the clipping path, but it's too much work. + */ + fit_copy(orig_dev, data, dx, raster, id, x, y, w, h); + { dev_proc_strip_tile_rectangle((*tile_proc)) = + dev_proc(dev, strip_tile_rectangle); + const byte *row; + int iy; + + for ( row = data, iy = 0; iy < h; row += raster, iy++ ) + { int ix; + for ( ix = 0; ix < w; ) + { int i0; +#define row_bit(i) (row[(i) >> 3] & (0x80 >> ((i) & 7))) + while ( ix < w && row_bit(ix + dx) == 0 ) + ix++; + for ( i0 = ix; ix < w && row_bit(ix + dx) != 0; ) + ix++; + if ( ix > i0 ) + { int code = (*tile_proc) + (dev, tile, i0 + x, iy + y, ix - i0, 1, + colors[0], colors[1], + gx_dc_phase(pdcolor).x, gx_dc_phase(pdcolor).y); + if ( code < 0 ) + return code; + } +#undef row_bit + } + } + } + return 0; +} + +/* Default implementation of strip_tile_rectangle */ +int +gx_default_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles, + int x, int y, int w, int h, gx_color_index color0, gx_color_index color1, + int px, int py) +{ /* Fill the rectangle in chunks. */ + int width = tiles->size.x; + int height = tiles->size.y; + int raster = tiles->raster; + int rwidth = tiles->rep_width; + int rheight = tiles->rep_height; + int shift = tiles->shift; + int xoff = + (shift == 0 ? px : + px + (y + py) / rheight * tiles->rep_shift); + int irx = ((rwidth & (rwidth - 1)) == 0 ? /* power of 2 */ + (x + xoff) & (rwidth - 1) : + (x + xoff) % rwidth); + int ry = ((rheight & (rheight - 1)) == 0 ? /* power of 2 */ + (y + py) & (rheight - 1) : + (y + py) % rheight); + int icw = width - irx; + int ch = height - ry; + byte *row = tiles->data + ry * raster; + dev_proc_copy_mono((*proc_mono)); + dev_proc_copy_color((*proc_color)); + int code; + +#ifdef DEBUG +if ( gs_debug_c('t') ) + { int ptx, pty; + const byte *ptp = tiles->data; + dprintf3("[t]tile %dx%d raster=%d;", + tiles->size.x, tiles->size.y, tiles->raster); + dprintf6(" x,y=%d,%d w,h=%d,%d p=%d,%d\n", + x, y, w, h, px, py); + for ( pty = 0; pty < tiles->size.y; pty++ ) + { dprintf(" "); + for ( ptx = 0; ptx < tiles->raster; ptx++ ) + dprintf1("%3x", *ptp++); + } + dputc('\n'); + } +#endif + + /* + * We should really make the following check before doing + * all the computations above, but since we expect devices + * to implement strip_tile_rectangle rather than tile_rectangle, + * the check will rarely succeed. + */ + if ( dev_proc(dev, tile_rectangle) != gx_default_tile_rectangle ) + { if ( shift == 0 ) + { /* + * Temporarily patch the tile_rectangle procedure in the + * device so we don't get into a recursion loop if the + * device has a tile_rectangle procedure that conditionally + * calls the strip_tile_rectangle procedure. + */ + dev_proc_tile_rectangle((*tile_proc)) = + dev_proc(dev, tile_rectangle); + int code; + + set_dev_proc(dev, tile_rectangle, gx_default_tile_rectangle); + code = (*tile_proc) + (dev, (const gx_tile_bitmap *)tiles, x, y, w, h, + color0, color1, px, py); + set_dev_proc(dev, tile_rectangle, tile_proc); + return code; + } + /* We should probably optimize this case too, for the benefit */ + /* of window systems, but we don't yet. */ + } + + if ( color0 == gx_no_color_index && color1 == gx_no_color_index ) + proc_color = dev_proc(dev, copy_color); + else + proc_color = 0, proc_mono = dev_proc(dev, copy_mono); + +/****** SHOULD ALSO PASS id IF COPYING A FULL TILE ******/ +#define real_copy_tile(srcx, tx, ty, tw, th)\ + code =\ + (proc_color != 0 ?\ + (*proc_color)(dev, row, srcx, raster, gx_no_bitmap_id, tx, ty, tw, th) :\ + (*proc_mono)(dev, row, srcx, raster, gx_no_bitmap_id, tx, ty, tw, th, color0, color1));\ + if ( code < 0 ) return_error(code);\ + return_if_interrupt() +#ifdef DEBUG +#define copy_tile(sx, tx, ty, tw, th)\ + if ( gs_debug_c('t') )\ + dprintf5(" copy sx=%d x=%d y=%d w=%d h=%d\n",\ + sx, tx, ty, tw, th);\ + real_copy_tile(sx, tx, ty, tw, th) +#else +#define copy_tile(sx, tx, ty, tw, th)\ + real_copy_tile(sx, tx, ty, tw, th) +#endif + if ( ch >= h ) + { /* Shallow operation */ + if ( icw >= w ) + { /* Just one (partial) tile to transfer. */ + copy_tile(irx, x, y, w, h); + } + else + { int ex = x + w; + int fex = ex - width; + int cx = x + icw; + + copy_tile(irx, x, y, icw, h); + while ( cx <= fex ) + { copy_tile(0, cx, y, width, h); + cx += width; + } + if ( cx < ex ) + { copy_tile(0, cx, y, ex - cx, h); + } + } + } + else if ( icw >= w && shift == 0 ) + { /* Narrow operation, no shift */ + int ey = y + h; + int fey = ey - height; + int cy = y + ch; + + copy_tile(irx, x, y, w, ch); + row = tiles->data; + do + { ch = (cy > fey ? ey - cy : height); + copy_tile(irx, x, cy, w, ch); + } + while ( (cy += ch) < ey ); + } + else + { /* Full operation. If shift != 0, some scan lines */ + /* may be narrow. We could test shift == 0 in advance */ + /* and use a slightly faster loop, but right now */ + /* we don't bother. */ + int ex = x + w, ey = y + h; + int fex = ex - width, fey = ey - height; + int cx, cy; + + for ( cy = y; ; ) + { if ( icw >= w ) + { copy_tile(irx, x, cy, w, ch); + } + else + { copy_tile(irx, x, cy, icw, ch); + cx = x + icw; + while ( cx <= fex ) + { copy_tile(0, cx, cy, width, ch); + cx += width; + } + if ( cx < ex ) + { copy_tile(0, cx, cy, ex - cx, ch); + } + } + if ( (cy += ch) >= ey ) break; + ch = (cy > fey ? ey - cy : height); + if ( (irx += shift) >= rwidth ) + irx -= rwidth; + icw = width - irx; + row = tiles->data; + } + } +#undef copy_tile +#undef real_copy_tile + return 0; +} + +int +gx_no_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ return_error(gs_error_unknownerror); /* not implemented */ +} +int +gx_default_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ return (*gx_default_strip_copy_rop_proc) + (dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, + x, y, width, height, phase_x, phase_y, lop); +} + +/* The following is not really a device procedure. See gxdevice.h. */ + +/* Create an ordinary memory device for page or band buffering. */ +int +gx_default_make_buffer_device(gx_device_memory *mdev, + gx_device *target, gs_memory_t *mem, bool for_band) +{ const gx_device_memory *mdproto = + gdev_mem_device_for_bits(target->color_info.depth); + + if ( mdproto == 0 ) + return_error(gs_error_rangecheck); + if ( target == (gx_device *)mdev ) + mdev->std_procs = mdproto->std_procs; + else + gs_make_mem_device(mdev, mdproto, mem, (for_band ? 1 : 0), + (target == (gx_device *)mdev ? 0 : target)); + return 0; +} + +/* ---------------- Default per-instance procedures ---------------- */ + +int +gx_default_install(gx_device *dev, gs_state *pgs) +{ return 0; +} + +int +gx_default_begin_page(gx_device *dev, gs_state *pgs) +{ return 0; +} + +int +gx_default_end_page(gx_device *dev, int reason, gs_state *pgs) +{ return (reason != 2 ? 1 : 0); +} + +/* ---------------- Unaligned copy operations ---------------- */ + +/* + * Implementing unaligned operations in terms of the standard aligned + * operations requires adjusting the bitmap origin and/or the raster + * to be aligned. Adjusting the origin is simple, but non-portable, + * since there is no portable way to determine the alignment of a pointer. + * Adjusting the raster requires doing the operation one scan line at a time. + */ + +int +gx_copy_mono_unaligned(gx_device *dev, const byte *data, + int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h, + gx_color_index zero, gx_color_index one) +{ dev_proc_copy_mono((*copy_mono)) = dev_proc(dev, copy_mono); + uint offset = (uint)(data - (const byte *)0) & (align_bitmap_mod - 1); + int step = raster & (align_bitmap_mod - 1); + + /* Adjust the origin. */ + data -= offset; + dx += offset << 3; + + /* Adjust the raster. */ + if ( !step ) + { /* No adjustment needed. */ + return (*copy_mono)(dev, data, dx, raster, id, + x, y, w, h, zero, one); + } + + /* Do the transfer one scan line at a time. */ + { const byte *p = data; + int d = dx; + int code = 0; + int i; + + for ( i = 0; i < h && code >= 0; + ++i, p += raster - step, d += step << 3 + ) + code = (*copy_mono)(dev, p, d, raster, gx_no_bitmap_id, + x, y + i, w, 1, zero, one); + return code; + } +} + +int +gx_copy_color_unaligned(gx_device *dev, const byte *data, + int data_x, int raster, gx_bitmap_id id, + int x, int y, int width, int height) +{ dev_proc_copy_color((*copy_color)) = dev_proc(dev, copy_color); + int depth = dev->color_info.depth; + uint offset = (uint)(data - (const byte *)0) & (align_bitmap_mod - 1); + int step = raster & (align_bitmap_mod - 1); + + /* + * Adjust the origin. + * We have to do something very special for 24-bit data, + * because that is the only depth that doesn't divide + * align_bitmap_mod exactly. In particular, we need to find + * M*B + R == 0 mod 3, where M is align_bitmap_mod, R is the + * offset value just calculated, and B is an integer unknown; + * the new value of offset will be M*B + R. + */ + if ( depth == 24 ) + offset += (offset % 3) * + (align_bitmap_mod * (3 - (align_bitmap_mod % 3))); + data -= offset; + data_x += (offset << 3) / depth; + + /* Adjust the raster. */ + if ( !step ) + { /* No adjustment needed. */ + return (*copy_color)(dev, data, data_x, raster, id, + x, y, width, height); + } + + /* Do the transfer one scan line at a time. */ + { const byte *p = data; + int d = data_x; + int dstep = (step << 3) / depth; + int code = 0; + int i; + + for ( i = 0; i < height && code >= 0; + ++i, p += raster - step, d += dstep + ) + code = (*copy_color)(dev, p, d, raster, gx_no_bitmap_id, + x, y + i, width, 1); + return code; + } +} + +int +gx_copy_alpha_unaligned(gx_device *dev, const byte *data, int data_x, + int raster, gx_bitmap_id id, int x, int y, int width, int height, + gx_color_index color, int depth) +{ dev_proc_copy_alpha((*copy_alpha)) = dev_proc(dev, copy_alpha); + uint offset = (uint)(data - (const byte *)0) & (align_bitmap_mod - 1); + int step = raster & (align_bitmap_mod - 1); + + /* Adjust the origin. */ + data -= offset; + data_x += (offset << 3) / depth; + + /* Adjust the raster. */ + if ( !step ) + { /* No adjustment needed. */ + return (*copy_alpha)(dev, data, data_x, raster, id, + x, y, width, height, color, depth); + } + + /* Do the transfer one scan line at a time. */ + { const byte *p = data; + int d = data_x; + int dstep = (step << 3) / depth; + int code = 0; + int i; + + for ( i = 0; i < height && code >= 0; + ++i, p += raster - step, d += dstep + ) + code = (*copy_alpha)(dev, p, d, raster, gx_no_bitmap_id, + x, y + i, width, 1, color, depth); + return code; + } +} diff --git a/pstoraster/gdevemap.c b/pstoraster/gdevemap.c new file mode 100644 index 0000000000..939a83c9d7 --- /dev/null +++ b/pstoraster/gdevemap.c @@ -0,0 +1,64 @@ +/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevemap.c */ +/* Mappings between StandardEncoding and ISOLatin1Encoding */ +#include "std.h" + +const byte far_data gs_map_std_to_iso[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 173, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 161, 162, 163, 0, 165, 0, 167, 164, 0, 0, 171, 0, 0, 0, 0, + 0, 0, 0, 0, 183, 0, 182, 0, 0, 0, 0, 187, 0, 0, 0, 191, + 0, 145, 180, 147, 148, 175, 150, 151, 168, 0, 154, 184, 0, 157, 158, 159, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 198, 0, 170, 0, 0, 0, 0, 0, 216, 0, 186, 0, 0, 0, 0, + 0, 230, 0, 0, 0, 144, 0, 0, 0, 248, 0, 223, 0, 0, 0, 0 +}; + +const byte far_data gs_map_iso_to_std[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 245, 193, 194, 195, 196, 197, 198, 199, 200, 0, 202, 203, 0, 205, 206, 207, + 32, 161, 162, 163, 168, 165, 0, 167, 200, 0, 227, 171, 0, 45, 0, 197, + 0, 0, 0, 0, 194, 0, 182, 180, 203, 0, 235, 187, 0, 0, 0, 191, + 0, 0, 0, 0, 0, 0, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 251, + 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 249, 0, 0, 0, 0, 0, 0, 0 +}; diff --git a/pstoraster/gdevht.h b/pstoraster/gdevht.h new file mode 100644 index 0000000000..77bf5f28b7 --- /dev/null +++ b/pstoraster/gdevht.h @@ -0,0 +1,47 @@ +/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevht.h */ +/* Definitions for halftoning device */ +/* Requires gxdevice.h */ +#include "gzht.h" + +/* + * A halftoning device converts between a non-halftoned device color space + * (e.g., 8-bit gray) and a halftoned space (e.g., 1-bit black and white). + * Currently, the target space must not exceed 8 bits per pixel, so that + * we can pack two target colors and a halftone level into a gx_color_index. + */ +#define ht_target_max_depth 8 +#define ht_level_depth (sizeof(gx_color_index) * 8 - ht_target_max_depth * 2) +typedef struct gx_device_ht_s { + gx_device_forward_common; + /* Following are set before opening. */ + const gx_device_halftone *dev_ht; + gs_int_point ht_phase; /* halftone phase from gstate */ + /* Following are computed when device is opened. */ + gs_int_point phase; /* halftone tile offset */ +} gx_device_ht; + +/* Macro for casting gx_device argument */ +#define htdev ((gx_device_ht *)dev) diff --git a/pstoraster/gdevm1.c b/pstoraster/gdevm1.c new file mode 100644 index 0000000000..f0787d56b3 --- /dev/null +++ b/pstoraster/gdevm1.c @@ -0,0 +1,689 @@ +/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevm1.c */ +/* Monobit "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +extern dev_proc_strip_copy_rop(mem_mono_strip_copy_rop); /* in gdevmrop.c */ + +/* Optionally, use the slow RasterOp implementations for testing. */ +/*#define USE_COPY_ROP*/ + +#ifdef USE_COPY_ROP +#include "gsrop.h" +#endif + +/* ================ Standard (byte-oriented) device ================ */ + +/* We went to a lot of trouble to optimize mem_mono_tile_rectangle. */ +/* It has a substantial effect on the total time at high resolutions. */ +/* However, it takes quite a lot of code, so we omit it on 16-bit systems. */ +#define OPTIMIZE_TILE (arch_sizeof_int > 2) + +/* Procedures */ +private dev_proc_map_rgb_color(mem_mono_map_rgb_color); +private dev_proc_map_color_rgb(mem_mono_map_color_rgb); +private dev_proc_copy_mono(mem_mono_copy_mono); +private dev_proc_fill_rectangle(mem_mono_fill_rectangle); +#if OPTIMIZE_TILE +private dev_proc_strip_tile_rectangle(mem_mono_strip_tile_rectangle); +#else +# define mem_mono_strip_tile_rectangle gx_default_strip_tile_rectangle +#endif + +/* The device descriptor. */ +/* The instance is public. */ +const gx_device_memory far_data mem_mono_device = + mem_full_alpha_device("image1", 0, 1, mem_open, + mem_mono_map_rgb_color, mem_mono_map_color_rgb, + mem_mono_copy_mono, gx_default_copy_color, mem_mono_fill_rectangle, + mem_get_bits, gx_default_map_cmyk_color, gx_no_copy_alpha, + mem_mono_strip_tile_rectangle, mem_mono_strip_copy_rop); + +/* Map color to/from RGB. This may be inverted. */ +private gx_color_index +mem_mono_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g, + gx_color_value b) +{ return (gx_default_w_b_map_rgb_color(dev, r, g, b) ^ + mdev->palette.data[0]) & 1; +} +private int +mem_mono_map_color_rgb(gx_device *dev, gx_color_index color, + gx_color_value prgb[3]) +{ return gx_default_w_b_map_color_rgb(dev, + (color ^ mdev->palette.data[0]) & 1, + prgb); +} + +/* Fill a rectangle with a color. */ +private int +mem_mono_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ +#ifdef USE_COPY_ROP + return mem_mono_copy_rop(dev, NULL, 0, 0, gx_no_bitmap_id, NULL, + NULL, NULL, + x, y, w, h, 0, 0, + (color ? rop3_1 : rop3_0)); +#else + fit_fill(dev, x, y, w, h); + bits_fill_rectangle(scan_line_base(mdev, y), x, mdev->raster, + -(mono_fill_chunk)color, w, h); + return 0; +#endif +} + +/* Convert x coordinate to byte offset in scan line. */ +#define x_to_byte(x) ((x) >> 3) + +/* Copy a monochrome bitmap. */ +#undef mono_masks +#define mono_masks mono_copy_masks + +/* Fetch a chunk from the source. */ +/* The source data are always stored big-endian. */ +/* Note that the macros always cast cptr, */ +/* so it doesn't matter what the type of cptr is. */ +/* cshift = chunk_bits - shift. */ +#undef chunk +#if arch_is_big_endian +# define chunk uint +# define cfetch_right(cptr, shift, cshift)\ + (cfetch_aligned(cptr) >> shift) +# define cfetch_left(cptr, shift, cshift)\ + (cfetch_aligned(cptr) << shift) +/* Fetch a chunk that straddles a chunk boundary. */ +# define cfetch2(cptr, cskew, skew)\ + (cfetch_left(cptr, cskew, skew) +\ + cfetch_right((const chunk *)(cptr) + 1, skew, cskew)) +#else /* little-endian */ +# define chunk bits16 +private const bits16 right_masks2[9] = { + 0xffff, 0x7f7f, 0x3f3f, 0x1f1f, 0x0f0f, 0x0707, 0x0303, 0x0101, 0x0000 +}; +private const bits16 left_masks2[9] = { + 0xffff, 0xfefe, 0xfcfc, 0xf8f8, 0xf0f0, 0xe0e0, 0xc0c0, 0x8080, 0x0000 +}; +# define ccont(cptr, off) (((const chunk *)(cptr))[off]) +# define cfetch_right(cptr, shift, cshift)\ + ((shift) < 8 ?\ + ((ccont(cptr, 0) >> (shift)) & right_masks2[shift]) +\ + (ccont(cptr, 0) << (cshift)) :\ + ((chunk)*(const byte *)(cptr) << (cshift)) & 0xff00) +# define cfetch_left(cptr, shift, cshift)\ + ((shift) < 8 ?\ + ((ccont(cptr, 0) << (shift)) & left_masks2[shift]) +\ + (ccont(cptr, 0) >> (cshift)) :\ + ((ccont(cptr, 0) & 0xff00) >> (cshift)) & 0xff) +/* Fetch a chunk that straddles a chunk boundary. */ +/* We can avoid testing the shift amount twice */ +/* by expanding the cfetch_left/right macros in-line. */ +# define cfetch2(cptr, cskew, skew)\ + ((cskew) < 8 ?\ + ((ccont(cptr, 0) << (cskew)) & left_masks2[cskew]) +\ + (ccont(cptr, 0) >> (skew)) +\ + (((chunk)(((const byte *)(cptr))[2]) << (cskew)) & 0xff00) :\ + (((ccont(cptr, 0) & 0xff00) >> (skew)) & 0xff) +\ + ((ccont(cptr, 1) >> (skew)) & right_masks2[skew]) +\ + (ccont(cptr, 1) << (cskew))) +#endif +/* Since source and destination are both always big-endian, */ +/* fetching an aligned chunk never requires byte swapping. */ +# define cfetch_aligned(cptr)\ + (*(const chunk *)(cptr)) + +/* copy_function and copy_shift get added together for dispatch */ +typedef enum { + copy_or = 0, copy_store, copy_and, copy_funny +} copy_function; +/* copy_right/left is not an enum, because compilers complain about */ +/* an enumeration clash when these are added to a copy_function. */ +#define copy_right ((copy_function)0) +#define copy_left ((copy_function)4) +typedef struct { + short invert; + ushort op; /* copy_function */ +} copy_mode; +/* Map from to copy_mode. */ +#define cm(i,op) { i, (ushort)op } +private copy_mode copy_modes[9] = { + cm(-1, copy_funny), /* NN */ + cm(-1, copy_and), /* N0 */ + cm(0, copy_or), /* N1 */ + cm(0, copy_and), /* 0N */ + cm(0, copy_funny), /* 00 */ + cm(0, copy_store), /* 01 */ + cm(-1, copy_or), /* 1N */ + cm(-1, copy_store), /* 10 */ + cm(0, copy_funny), /* 11 */ +}; +private int +mem_mono_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ +#ifdef USE_COPY_ROP + return mem_mono_copy_rop(dev, base, sourcex, sraster, id, NULL, + NULL, NULL, + x, y, w, h, 0, 0, + ((zero == gx_no_color_index ? rop3_D : + zero == 0 ? rop3_0 : rop3_1) & ~rop3_S) | + ((one == gx_no_color_index ? rop3_D : + one == 0 ? rop3_0 : rop3_1) & rop3_S)); +#else /* !USE_COPY_ROP */ + register const byte *bptr; /* actually chunk * */ + int dbit, wleft; + uint mask; + copy_mode mode; +#define function (copy_function)(mode.op) + declare_scan_ptr_as(dbptr, byte *); +#define optr ((chunk *)dbptr) + register int skew; + register uint invert; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); +#if gx_no_color_index_value != -1 /* hokey! */ + if ( zero == gx_no_color_index ) zero = -1; + if ( one == gx_no_color_index ) one = -1; +#endif +#define izero (int)zero +#define ione (int)one + mode = copy_modes[izero + izero + izero + ione + 4]; +#undef izero +#undef ione + invert = (uint)(int)mode.invert; /* load register */ + setup_rect_as(dbptr, byte *); + bptr = base + ((sourcex & ~chunk_align_bit_mask) >> 3); + dbit = x & chunk_align_bit_mask; + skew = dbit - (sourcex & chunk_align_bit_mask); +/* Macros for writing partial chunks. */ +/* The destination pointer is always named optr, */ +/* and must be declared as chunk *. */ +/* cinvert may be temporarily redefined. */ +#define cinvert(bits) ((bits) ^ invert) +#define write_or_masked(bits, mask, off)\ + optr[off] |= (cinvert(bits) & mask) +#define write_store_masked(bits, mask, off)\ + optr[off] = ((optr[off] & ~mask) | (cinvert(bits) & mask)) +#define write_and_masked(bits, mask, off)\ + optr[off] &= (cinvert(bits) | ~mask) +/* Macros for writing full chunks. */ +#define write_or(bits) *optr |= cinvert(bits) +#define write_store(bits) *optr = cinvert(bits) +#define write_and(bits) *optr &= cinvert(bits) +/* Macro for incrementing to next chunk. */ +#define next_x_chunk\ + bptr += chunk_bytes; dbptr += chunk_bytes +/* Common macro for the end of each scan line. */ +#define end_y_loop(sdelta, ddelta)\ + if ( --h == 0 ) break;\ + bptr += sdelta; dbptr += ddelta + if ( (wleft = w + dbit - chunk_bits) <= 0 ) + { /* The entire operation fits in one (destination) chunk. */ + set_mono_thin_mask(mask, w, dbit); +#define write_single(wr_op, src)\ + for ( ; ; )\ + { wr_op(src, mask, 0);\ + end_y_loop(sraster, draster);\ + } +#define write1_loop(src)\ + switch ( function ) {\ + case copy_or: write_single(write_or_masked, src); break;\ + case copy_store: write_single(write_store_masked, src); break;\ + case copy_and: write_single(write_and_masked, src); break;\ + default: goto funny;\ + } + if ( skew >= 0 ) /* single -> single, right/no shift */ + { if ( skew == 0 ) /* no shift */ + { write1_loop(cfetch_aligned(bptr)); + } + else /* right shift */ + { int cskew = chunk_bits - skew; + write1_loop(cfetch_right(bptr, skew, cskew)); + } + } + else if ( wleft <= skew ) /* single -> single, left shift */ + { int cskew = chunk_bits + skew; + skew = -skew; + write1_loop(cfetch_left(bptr, skew, cskew)); + } + else /* double -> single */ + { int cskew = -skew; + skew += chunk_bits; + write1_loop(cfetch2(bptr, cskew, skew)); + } +#undef write1_loop +#undef write_single + } + else if ( wleft <= skew ) + { /* 1 source chunk -> 2 destination chunks. */ + /* This is an important special case for */ + /* both characters and halftone tiles. */ + uint rmask; + int cskew = chunk_bits - skew; + set_mono_left_mask(mask, dbit); + set_mono_right_mask(rmask, wleft); +#undef cinvert +#define cinvert(bits) (bits) /* pre-inverted here */ +#if arch_is_big_endian /* no byte swapping */ +# define write_1to2(wr_op)\ + for ( ; ; )\ + { register uint bits = cfetch_aligned(bptr) ^ invert;\ + wr_op(bits >> skew, mask, 0);\ + wr_op(bits << cskew, rmask, 1);\ + end_y_loop(sraster, draster);\ + } +#else /* byte swapping */ +# define write_1to2(wr_op)\ + for ( ; ; )\ + { wr_op(cfetch_right(bptr, skew, cskew) ^ invert, mask, 0);\ + wr_op(cfetch_left(bptr, cskew, skew) ^ invert, rmask, 1);\ + end_y_loop(sraster, draster);\ + } +#endif + switch ( function ) + { + case copy_or: write_1to2(write_or_masked); break; + case copy_store: write_1to2(write_store_masked); break; + case copy_and: write_1to2(write_and_masked); break; + default: goto funny; + } +#undef cinvert +#define cinvert(bits) ((bits) ^ invert) +#undef write_1to2 + } + else + { /* More than one source chunk and more than one */ + /* destination chunk are involved. */ + uint rmask; + int words = (wleft & ~chunk_bit_mask) >> 3; + uint sskip = sraster - words; + uint dskip = draster - words; + register uint bits; + set_mono_left_mask(mask, dbit); + set_mono_right_mask(rmask, wleft & chunk_bit_mask); + if ( skew == 0 ) /* optimize the aligned case */ + { +#define write_aligned(wr_op, wr_op_masked)\ + for ( ; ; )\ + { int count = wleft;\ + /* Do first partial chunk. */\ + wr_op_masked(cfetch_aligned(bptr), mask, 0);\ + /* Do full chunks. */\ + while ( (count -= chunk_bits) >= 0 )\ + { next_x_chunk; wr_op(cfetch_aligned(bptr)); }\ + /* Do last chunk */\ + if ( count > -chunk_bits )\ + { wr_op_masked(cfetch_aligned(bptr + chunk_bytes), rmask, 1); }\ + end_y_loop(sskip, dskip);\ + } + switch ( function ) + { + case copy_or: + write_aligned(write_or, write_or_masked); + break; + case copy_store: + write_aligned(write_store, write_store_masked); + break; + case copy_and: + write_aligned(write_and, write_and_masked); + break; + default: + goto funny; + } +#undef write_aligned + } + else /* not aligned */ + { int ccase = + (skew >= 0 ? copy_right : + ((bptr += chunk_bytes), copy_left)) + + (int)function; + int cskew = -skew & chunk_bit_mask; + skew &= chunk_bit_mask; + for ( ; ; ) + { int count = wleft; +#define prefetch_right\ + bits = cfetch_right(bptr, skew, cskew) +#define prefetch_left\ + bits = cfetch2(bptr - chunk_bytes, cskew, skew) +#define write_unaligned(wr_op, wr_op_masked)\ + wr_op_masked(bits, mask, 0);\ + /* Do full chunks. */\ + while ( count >= chunk_bits )\ + { bits = cfetch2(bptr, cskew, skew);\ + next_x_chunk; wr_op(bits); count -= chunk_bits;\ + }\ + /* Do last chunk */\ + if ( count > 0 )\ + { bits = cfetch_left(bptr, cskew, skew);\ + if ( count > skew ) bits += cfetch_right(bptr + chunk_bytes, skew, cskew);\ + wr_op_masked(bits, rmask, 1);\ + } + switch ( ccase ) + { + case copy_or + copy_left: + prefetch_left; goto uor; + case copy_or + copy_right: + prefetch_right; +uor: write_unaligned(write_or, write_or_masked); + break; + case copy_store + copy_left: + prefetch_left; goto ustore; + case copy_store + copy_right: + prefetch_right; +ustore: write_unaligned(write_store, write_store_masked); + break; + case copy_and + copy_left: + prefetch_left; goto uand; + case copy_and + copy_right: + prefetch_right; +uand: write_unaligned(write_and, write_and_masked); + break; + default: + goto funny; + } + end_y_loop(sskip, dskip); +#undef write_unaligned +#undef prefetch_left +#undef prefetch_right + } + } + } +#undef end_y_loop +#undef next_x_chunk + return 0; + /* Handle the funny cases that aren't supposed to happen. */ +funny: return (invert ? -1 : mem_mono_fill_rectangle(dev, x, y, w, h, zero)); +#undef optr +#endif /* !USE_COPY_ROP */ +} + +#if OPTIMIZE_TILE /**************** ****************/ + +/* Strip-tile with a monochrome halftone. */ +/* This is a performance bottleneck for monochrome devices, */ +/* so we re-implement it, even though it takes a lot of code. */ +private int +mem_mono_strip_tile_rectangle(gx_device *dev, + register const gx_strip_bitmap *tiles, + int tx, int y, int tw, int th, gx_color_index color0, gx_color_index color1, + int px, int py) +{ +#ifdef USE_COPY_ROP + return mem_mono_strip_copy_rop(dev, NULL, 0, 0, tile->id, NULL, + tiles, NULL, + tx, y, tw, th, px, py, + ((color0 == gx_no_color_index ? rop3_D : + color0 == 0 ? rop3_0 : rop3_1) & ~rop3_T) | + ((color1 == gx_no_color_index ? rop3_D : + color1 == 0 ? rop3_0 : rop3_1) & rop3_T)); +#else /* !USE_COPY_ROP */ + register uint invert; + int sraster; + uint tile_bits_size; + const byte *base; + const byte *end; + int x, rw, w, h; + register const byte *bptr; /* actually chunk * */ + int dbit, wleft; + uint mask; + byte *dbase; + declare_scan_ptr_as(dbptr, byte *); +#define optr ((chunk *)dbptr) + register int skew; + + /* This implementation doesn't handle strips yet. */ + if ( color0 != (color1 ^ 1) || tiles->shift != 0 ) + return gx_default_strip_tile_rectangle(dev, tiles, tx, y, tw, th, + color0, color1, px, py); + fit_fill(dev, tx, y, tw, th); + invert = -(uint)color0; + sraster = tiles->raster; + base = tiles->data + ((y + py) % tiles->rep_height) * sraster; + tile_bits_size = tiles->size.y * sraster; + end = tiles->data + tile_bits_size; +#undef end_y_loop +#define end_y_loop(sdelta, ddelta)\ + if ( --h == 0 ) break;\ + if ( end - bptr <= sdelta ) /* wrap around */\ + bptr -= tile_bits_size;\ + bptr += sdelta; dbptr += ddelta + draster = mdev->raster; + dbase = scan_line_base(mdev, y); + x = tx; + rw = tw; + /* + * The outermost loop here works horizontally, one iteration per + * copy of the tile. Note that all iterations except the first + * have sourcex = 0. + */ + { int sourcex = (x + px) % tiles->rep_width; + w = tiles->size.x - sourcex; + bptr = base + ((sourcex & ~chunk_align_bit_mask) >> 3); + dbit = x & chunk_align_bit_mask; + skew = dbit - (sourcex & chunk_align_bit_mask); + } +outer: if ( w > rw ) + w = rw; + h = th; + dbptr = dbase + ((x >> 3) & -chunk_align_bytes); + if ( (wleft = w + dbit - chunk_bits) <= 0 ) + { /* The entire operation fits in one (destination) chunk. */ + set_mono_thin_mask(mask, w, dbit); +#define write1_loop(src)\ + for ( ; ; )\ + { write_store_masked(src, mask, 0);\ + end_y_loop(sraster, draster);\ + } + if ( skew >= 0 ) /* single -> single, right/no shift */ + { if ( skew == 0 ) /* no shift */ + { write1_loop(cfetch_aligned(bptr)); + } + else /* right shift */ + { int cskew = chunk_bits - skew; + write1_loop(cfetch_right(bptr, skew, cskew)); + } + } + else if ( wleft <= skew ) /* single -> single, left shift */ + { int cskew = chunk_bits + skew; + skew = -skew; + write1_loop(cfetch_left(bptr, skew, cskew)); + } + else /* double -> single */ + { int cskew = -skew; + skew += chunk_bits; + write1_loop(cfetch2(bptr, cskew, skew)); + } +#undef write1_loop + } + else if ( wleft <= skew ) + { /* 1 source chunk -> 2 destination chunks. */ + /* This is an important special case for */ + /* both characters and halftone tiles. */ + uint rmask; + int cskew = chunk_bits - skew; + set_mono_left_mask(mask, dbit); + set_mono_right_mask(rmask, wleft); +#if arch_is_big_endian /* no byte swapping */ +#undef cinvert +#define cinvert(bits) (bits) /* pre-inverted here */ + for ( ; ; ) + { register uint bits = cfetch_aligned(bptr) ^ invert; + write_store_masked(bits >> skew, mask, 0); + write_store_masked(bits << cskew, rmask, 1); + end_y_loop(sraster, draster); + } +#undef cinvert +#define cinvert(bits) ((bits) ^ invert) +#else /* byte swapping */ + for ( ; ; ) + { write_store_masked(cfetch_right(bptr, skew, cskew), mask, 0); + write_store_masked(cfetch_left(bptr, cskew, skew), rmask, 1); + end_y_loop(sraster, draster); + } +#endif + } + else + { /* More than one source chunk and more than one */ + /* destination chunk are involved. */ + uint rmask; + int words = (wleft & ~chunk_bit_mask) >> 3; + uint sskip = sraster - words; + uint dskip = draster - words; + register uint bits; +#define next_x_chunk\ + bptr += chunk_bytes; dbptr += chunk_bytes + + set_mono_right_mask(rmask, wleft & chunk_bit_mask); + if ( skew == 0 ) /* optimize the aligned case */ + { if ( dbit == 0 ) + mask = 0; + else + set_mono_left_mask(mask, dbit); + for ( ; ; ) + { int count = wleft; + /* Do first partial chunk. */ + if ( mask ) + write_store_masked(cfetch_aligned(bptr), mask, 0); + else + write_store(cfetch_aligned(bptr)); + /* Do full chunks. */ + while ( (count -= chunk_bits) >= 0 ) + { next_x_chunk; + write_store(cfetch_aligned(bptr)); + } + /* Do last chunk */ + if ( count > -chunk_bits ) + { write_store_masked(cfetch_aligned(bptr + chunk_bytes), rmask, 1); + } + end_y_loop(sskip, dskip); + } + } + else /* not aligned */ + { bool case_right = + (skew >= 0 ? true : + ((bptr += chunk_bytes), false)); + int cskew = -skew & chunk_bit_mask; + + skew &= chunk_bit_mask; + set_mono_left_mask(mask, dbit); + for ( ; ; ) + { int count = wleft; + if ( case_right ) + bits = cfetch_right(bptr, skew, cskew); + else + bits = cfetch2(bptr - chunk_bytes, cskew, skew); + write_store_masked(bits, mask, 0); + /* Do full chunks. */ + while ( count >= chunk_bits ) + { bits = cfetch2(bptr, cskew, skew); + next_x_chunk; + write_store(bits); + count -= chunk_bits; + } + /* Do last chunk */ + if ( count > 0 ) + { bits = cfetch_left(bptr, cskew, skew); + if ( count > skew ) + bits += cfetch_right(bptr + chunk_bytes, skew, cskew); + write_store_masked(bits, rmask, 1); + } + end_y_loop(sskip, dskip); + } + } + } +#undef end_y_loop +#undef next_x_chunk +#undef optr + if ( (rw -= w) > 0 ) + { x += w; + w = tiles->size.x; + bptr = base; + skew = dbit = x & chunk_align_bit_mask; + goto outer; + } + return 0; +#endif /* !USE_COPY_ROP */ +} + +#endif /**************** ****************/ + +/* ================ "Word"-oriented device ================ */ + +/* Note that on a big-endian machine, this is the same as the */ +/* standard byte-oriented-device. */ + +#if !arch_is_big_endian + +/* Procedures */ +private dev_proc_copy_mono(mem1_word_copy_mono); +private dev_proc_fill_rectangle(mem1_word_fill_rectangle); +#define mem1_word_strip_tile_rectangle gx_default_strip_tile_rectangle + +/* Here is the device descriptor. */ +const gx_device_memory far_data mem_mono_word_device = + mem_full_alpha_device("image1w", 0, 1, mem_open, + mem_mono_map_rgb_color, mem_mono_map_color_rgb, + mem1_word_copy_mono, gx_default_copy_color, mem1_word_fill_rectangle, + mem_word_get_bits, gx_default_map_cmyk_color, gx_no_copy_alpha, + mem1_word_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Fill a rectangle with a color. */ +private int +mem1_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ byte *base; + uint raster; + fit_fill(dev, x, y, w, h); + base = scan_line_base(mdev, y); + raster = mdev->raster; + mem_swap_byte_rect(base, raster, x, w, h, true); + bits_fill_rectangle(base, x, raster, -(mono_fill_chunk)color, w, h); + mem_swap_byte_rect(base, raster, x, w, h, true); + return 0; +} + +/* Copy a bitmap. */ +private int +mem1_word_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ byte *row; + uint raster; + bool store; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + store = (zero != gx_no_color_index && one != gx_no_color_index); + mem_swap_byte_rect(row, raster, x, w, h, store); + mem_mono_copy_mono(dev, base, sourcex, sraster, id, + x, y, w, h, zero, one); + mem_swap_byte_rect(row, raster, x, w, h, false); + return 0; +} + +#endif /* !arch_is_big_endian */ diff --git a/pstoraster/gdevm16.c b/pstoraster/gdevm16.c new file mode 100644 index 0000000000..149a72129e --- /dev/null +++ b/pstoraster/gdevm16.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevm16.c */ +/* 16-bit-per-pixel "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +#undef chunk +#define chunk byte + +/* The 16 bits are divided 5 for red, 6 for green, and 5 for blue. */ +/* Note that the bits must always be kept in big-endian order. */ + +/* Procedures */ +declare_mem_map_procs(mem_true16_map_rgb_color, mem_true16_map_color_rgb); +declare_mem_procs(mem_true16_copy_mono, mem_true16_copy_color, mem_true16_fill_rectangle); + +/* The device descriptor. */ +const gx_device_memory far_data mem_true16_device = + mem_device("image16", 16, 0, + mem_true16_map_rgb_color, mem_true16_map_color_rgb, + mem_true16_copy_mono, mem_true16_copy_color, mem_true16_fill_rectangle, + gx_no_strip_copy_rop); + +/* Map a r-g-b color to a color index. */ +private gx_color_index +mem_true16_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g, + gx_color_value b) +{ return ((r >> (gx_color_value_bits - 5)) << 11) + + ((g >> (gx_color_value_bits - 6)) << 5) + + (b >> (gx_color_value_bits - 5)); +} + +/* Map a color index to a r-g-b color. */ +private int +mem_true16_map_color_rgb(gx_device *dev, gx_color_index color, + gx_color_value prgb[3]) +{ ushort value = color >> 11; + prgb[0] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits); + value = (color >> 6) & 0x7f; + prgb[1] = ((value << 10) + (value << 4) + (value >> 2)) >> (16 - gx_color_value_bits); + value = color & 0x3f; + prgb[2] = ((value << 11) + (value << 6) + (value << 1) + (value >> 4)) >> (16 - gx_color_value_bits); + return 0; +} + +/* Convert x coordinate to byte offset in scan line. */ +#undef x_to_byte +#define x_to_byte(x) ((x) << 1) + +/* Fill a rectangle with a color. */ +private int +mem_true16_fill_rectangle(gx_device *dev, + int x, int y, int w, int h, gx_color_index color) +{ +#if arch_is_big_endian +# define color16 ((ushort)color) +#else + ushort color16 = ((uint)(byte)color << 8) + ((ushort)color >> 8); +#endif + declare_scan_ptr(dest); + fit_fill(dev, x, y, w, h); + setup_rect(dest); + while ( h-- > 0 ) + { ushort *pptr = (ushort *)dest; + int cnt = w; + do { *pptr++ = color16; } while ( --cnt > 0 ); + inc_ptr(dest, draster); + } + return 0; +#undef color16 +} + +/* Copy a monochrome bitmap. */ +private int +mem_true16_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ +#if arch_is_big_endian +# define zero16 ((ushort)zero) +# define one16 ((ushort)one) +#else + ushort zero16 = ((uint)(byte)zero << 8) + ((ushort)zero >> 8); + ushort one16 = ((uint)(byte)one << 8) + ((ushort)one >> 8); +#endif + const byte *line; + int first_bit; + declare_scan_ptr(dest); + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base + (sourcex >> 3); + first_bit = 0x80 >> (sourcex & 7); + while ( h-- > 0 ) + { register ushort *pptr = (ushort *)dest; + const byte *sptr = line; + register int sbyte = *sptr++; + register int bit = first_bit; + int count = w; + do + { if ( sbyte & bit ) + { if ( one != gx_no_color_index ) + *pptr = one16; + } + else + { if ( zero != gx_no_color_index ) + *pptr = zero16; + } + if ( (bit >>= 1) == 0 ) + bit = 0x80, sbyte = *sptr++; + pptr++; + } + while ( --count > 0 ); + line += sraster; + inc_ptr(dest, draster); + } + return 0; +#undef zero16 +#undef one16 +} + +/* Copy a color bitmap. */ +private int +mem_true16_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h); + return 0; +} diff --git a/pstoraster/gdevm2.c b/pstoraster/gdevm2.c new file mode 100644 index 0000000000..f68ccea72c --- /dev/null +++ b/pstoraster/gdevm2.c @@ -0,0 +1,244 @@ +/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevm2.c */ +/* 2-bit-per-pixel "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +/**************** NOTE: copy_rop only works for gray scale ****************/ +extern dev_proc_strip_copy_rop(mem_gray_strip_copy_rop); + +/* ================ Standard (byte-oriented) device ================ */ + +#undef chunk +#define chunk byte +#define fpat(byt) mono_fill_make_pattern(byt) + +/* Procedures */ +declare_mem_procs(mem_mapped2_copy_mono, mem_mapped2_copy_color, mem_mapped2_fill_rectangle); + +/* The device descriptor. */ +const gx_device_memory far_data mem_mapped2_device = + mem_device("image2", 2, 0, + mem_mapped_map_rgb_color, mem_mapped_map_color_rgb, + mem_mapped2_copy_mono, mem_mapped2_copy_color, mem_mapped2_fill_rectangle, + mem_gray_strip_copy_rop); + +/* Convert x coordinate to byte offset in scan line. */ +#undef x_to_byte +#define x_to_byte(x) ((x) >> 2) + +/* Define the 2-bit fill patterns. */ +static const mono_fill_chunk tile_patterns[4] = +{ fpat(0x00), fpat(0x55), fpat(0xaa), fpat(0xff) +}; + +/* Fill a rectangle with a color. */ +private int +mem_mapped2_fill_rectangle(gx_device *dev, + int x, int y, int w, int h, gx_color_index color) +{ fit_fill(dev, x, y, w, h); + bits_fill_rectangle(scan_line_base(mdev, y), x << 1, mdev->raster, + tile_patterns[color], w << 1, h); + return 0; +} + +/* Copy a bitmap. */ +private int +mem_mapped2_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ const byte *line; + int first_bit; + byte first_mask, b0, b1, bxor, left_mask, right_mask; + static const byte btab[4] = { 0, 0x55, 0xaa, 0xff }; + static const byte bmask[4] = { 0xc0, 0x30, 0xc, 3 }; + static const byte lmask[4] = { 0, 0xc0, 0xf0, 0xfc }; + declare_scan_ptr(dest); + + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base + (sourcex >> 3); + first_bit = 0x80 >> (sourcex & 7); + first_mask = bmask[x & 3]; + left_mask = lmask[x & 3]; + right_mask = ~lmask[(x + w) & 3]; + if ( (x & 3) + w <= 4 ) + left_mask = right_mask = left_mask | right_mask; + b0 = btab[zero & 3]; + b1 = btab[one & 3]; + bxor = b0 ^ b1; + while ( h-- > 0 ) + { register byte *pptr = (byte *)dest; + const byte *sptr = line; + register int sbyte = *sptr++; + register int bit = first_bit; + register byte mask = first_mask; + int count = w; + + /* We have 4 cases, of which only 2 really matter. */ + if ( one != gx_no_color_index ) + { if ( zero != gx_no_color_index ) + { /* Copying an opaque bitmap. */ + byte data = + (*pptr & left_mask) | (b0 & ~left_mask); + do + { if ( sbyte & bit ) + data ^= bxor & mask; + if ( (bit >>= 1) == 0 ) + bit = 0x80, sbyte = *sptr++; + if ( (mask >>= 2) == 0 ) + mask = 0xc0, *pptr++ = data, data = b0; + } + while ( --count > 0 ); + if ( mask != 0xc0 ) + *pptr = + (*pptr & right_mask) | (data & ~right_mask); + } + else + { /* Filling a mask. */ + do + { if ( sbyte & bit ) + *pptr = (*pptr & ~mask) + (b1 & mask); + if ( (bit >>= 1) == 0 ) + bit = 0x80, sbyte = *sptr++; + if ( (mask >>= 2) == 0 ) + mask = 0xc0, pptr++; + } + while ( --count > 0 ); + } + } + else + { /* Some other case. */ + do + { if ( !(sbyte & bit) ) + { if ( zero != gx_no_color_index ) + *pptr = (*pptr & ~mask) + (b0 & mask); + } + if ( (bit >>= 1) == 0 ) + bit = 0x80, sbyte = *sptr++; + if ( (mask >>= 2) == 0 ) + mask = 0xc0, pptr++; + } + while ( --count > 0 ); + } + line += sraster; + inc_ptr(dest, draster); + } + return 0; +} + +/* Copy a color bitmap. */ +private int +mem_mapped2_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ int code; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + /* Use monobit copy_mono. */ + /* Patch the width in the device temporarily. */ + dev->width <<= 1; + code = (*dev_proc(&mem_mono_device, copy_mono)) + (dev, base, sourcex << 1, sraster, id, + x << 1, y, w << 1, h, (gx_color_index)0, (gx_color_index)1); + /* Restore the correct width. */ + dev->width >>= 1; + return code; +} + +/* ================ "Word"-oriented device ================ */ + +/* Note that on a big-endian machine, this is the same as the */ +/* standard byte-oriented-device. */ + +#if !arch_is_big_endian + +/* Procedures */ +declare_mem_procs(mem2_word_copy_mono, mem2_word_copy_color, mem2_word_fill_rectangle); + +/* Here is the device descriptor. */ +const gx_device_memory far_data mem_mapped2_word_device = + mem_full_device("image2w", 2, 0, mem_open, + mem_mapped_map_rgb_color, mem_mapped_map_color_rgb, + mem2_word_copy_mono, mem2_word_copy_color, mem2_word_fill_rectangle, + mem_word_get_bits, gx_default_map_cmyk_color, + gx_default_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Fill a rectangle with a color. */ +private int +mem2_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ byte *base; + uint raster; + fit_fill(dev, x, y, w, h); + base = scan_line_base(mdev, y); + raster = mdev->raster; + mem_swap_byte_rect(base, raster, x << 1, w << 1, h, true); + bits_fill_rectangle(base, x << 1, raster, + tile_patterns[color], w << 1, h); + mem_swap_byte_rect(base, raster, x << 1, w << 1, h, true); + return 0; +} + +/* Copy a bitmap. */ +private int +mem2_word_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ byte *row; + uint raster; + bool store; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + store = (zero != gx_no_color_index && one != gx_no_color_index); + mem_swap_byte_rect(row, raster, x << 1, w << 1, h, store); + mem_mapped2_copy_mono(dev, base, sourcex, sraster, id, + x, y, w, h, zero, one); + mem_swap_byte_rect(row, raster, x << 1, w << 1, h, false); + return 0; +} + +/* Copy a color bitmap. */ +private int +mem2_word_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ int code; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + /* Use monobit copy_mono. */ + /* Patch the width in the device temporarily. */ + dev->width <<= 1; + code = (*dev_proc(&mem_mono_word_device, copy_mono)) + (dev, base, sourcex << 1, sraster, id, + x << 1, y, w << 1, h, (gx_color_index)0, (gx_color_index)1); + /* Restore the correct width. */ + dev->width >>= 1; + return code; +} + +#endif /* !arch_is_big_endian */ diff --git a/pstoraster/gdevm24.c b/pstoraster/gdevm24.c new file mode 100644 index 0000000000..110845525f --- /dev/null +++ b/pstoraster/gdevm24.c @@ -0,0 +1,484 @@ +/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevm24.c */ +/* 24-bit-per-pixel "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +extern dev_proc_strip_copy_rop(mem_gray8_rgb24_strip_copy_rop); /* in gdevmrop.c */ +#define mem_true24_strip_copy_rop mem_gray8_rgb24_strip_copy_rop + +/* ================ Standard (byte-oriented) device ================ */ + +#undef chunk +#define chunk byte + +/* Procedures */ +declare_mem_procs(mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle); +private dev_proc_copy_alpha(mem_true24_copy_alpha); + +/* The device descriptor. */ +const gx_device_memory far_data mem_true24_device = + mem_full_alpha_device("image24", 24, 0, mem_open, + gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb, + mem_true24_copy_mono, mem_true24_copy_color, mem_true24_fill_rectangle, + mem_get_bits, gx_default_map_cmyk_color, mem_true24_copy_alpha, + gx_default_strip_tile_rectangle, mem_true24_strip_copy_rop); + +/* Convert x coordinate to byte offset in scan line. */ +#undef x_to_byte +#define x_to_byte(x) ((x) * 3) + +/* Unpack a color into its bytes. */ +#define declare_unpack_color(r, g, b, color)\ + byte r = (byte)(color >> 16);\ + byte g = (byte)((uint)color >> 8);\ + byte b = (byte)color +/* Put a 24-bit color into the bitmap. */ +#define put3(ptr, r, g, b)\ + (ptr)[0] = r, (ptr)[1] = g, (ptr)[2] = b +/* Put 4 bytes of color into the bitmap. */ +#define putw(ptr, wxyz)\ + *(bits32 *)(ptr) = (wxyz) +/* Load the 3-word 24-bit-color cache. */ +/* Free variables: [m]dev, rgbr, gbrg, brgb. */ +#if arch_is_big_endian +# define set_color24_cache(crgb, r, g, b)\ + mdev->color24.rgbr = rgbr = ((bits32)(crgb) << 8) | (r),\ + mdev->color24.gbrg = gbrg = (rgbr << 8) | (g),\ + mdev->color24.brgb = brgb = (gbrg << 8) | (b),\ + mdev->color24.rgb = (crgb) +#else +# define set_color24_cache(crgb, r, g, b)\ + mdev->color24.rgbr = rgbr =\ + ((bits32)(r) << 24) | ((bits32)(b) << 16) |\ + ((bits16)(g) << 8) | (r),\ + mdev->color24.brgb = brgb = (rgbr << 8) | (b),\ + mdev->color24.gbrg = gbrg = (brgb << 8) | (g),\ + mdev->color24.rgb = (crgb) +#endif + +/* Fill a rectangle with a color. */ +private int +mem_true24_fill_rectangle(gx_device *dev, + int x, int y, int w, int h, gx_color_index color) +{ declare_unpack_color(r, g, b, color); + declare_scan_ptr(dest); + fit_fill_xywh(dev, x, y, w, h); /* don't check w <= 0 or h <= 0 */ + setup_rect(dest); + if ( w >= 5 ) + { if ( r == g && r == b) + { +#if 1 + /* We think we can do better than the library's memset.... */ + int bcntm7 = w * 3 - 7; + register bits32 cword = color | (color << 24); + while ( h-- > 0 ) + { register byte *pptr = dest; + byte *limit = pptr + bcntm7; + /* We want to store full words, but we have to */ + /* guarantee that they are word-aligned. */ + switch ( x & 3 ) + { + case 3: *pptr++ = (byte)cword; + case 2: *pptr++ = (byte)cword; + case 1: *pptr++ = (byte)cword; + case 0: ; + } + /* Even with w = 5, we always store at least */ + /* 3 full words, regardless of the starting x. */ + *(bits32 *)pptr = + ((bits32 *)pptr)[1] = + ((bits32 *)pptr)[2] = cword; + pptr += 12; + while ( pptr < limit ) + { *(bits32 *)pptr = + ((bits32 *)pptr)[1] = cword; + pptr += 8; + } + switch ( pptr - limit ) + { + case 0: pptr[6] = (byte)cword; + case 1: pptr[5] = (byte)cword; + case 2: pptr[4] = (byte)cword; + case 3: *(bits32 *)pptr = cword; + break; + case 4: pptr[2] = (byte)cword; + case 5: pptr[1] = (byte)cword; + case 6: pptr[0] = (byte)cword; + case 7: ; + } + inc_ptr(dest, draster); + } +#else + int bcnt = w * 3; + while ( h-- > 0 ) + { memset(dest, r, bcnt); + inc_ptr(dest, draster); + } +#endif + } + else + { int x3 = -x & 3, ww = w - x3; /* we know ww >= 2 */ + bits32 rgbr, gbrg, brgb; + if ( mdev->color24.rgb == color ) + rgbr = mdev->color24.rgbr, + gbrg = mdev->color24.gbrg, + brgb = mdev->color24.brgb; + else + set_color24_cache(color, r, g, b); + while ( h-- > 0 ) + { register byte *pptr = dest; + int w1 = ww; + switch ( x3 ) + { + case 1: + put3(pptr, r, g, b); + pptr += 3; break; + case 2: + pptr[0] = r; pptr[1] = g; + putw(pptr + 2, brgb); + pptr += 6; break; + case 3: + pptr[0] = r; + putw(pptr + 1, gbrg); + putw(pptr + 5, brgb); + pptr += 9; break; + case 0: + ; + } + while ( w1 >= 4 ) + { putw(pptr, rgbr); + putw(pptr + 4, gbrg); + putw(pptr + 8, brgb); + pptr += 12; + w1 -= 4; + } + switch ( w1 ) + { + case 1: + put3(pptr, r, g, b); + break; + case 2: + putw(pptr, rgbr); + pptr[4] = g; pptr[5] = b; + break; + case 3: + putw(pptr, rgbr); + putw(pptr + 4, gbrg); + pptr[8] = b; + break; + case 0: + ; + } + inc_ptr(dest, draster); + } + } + } + else if ( h > 0 ) /* w < 5 */ + switch ( w ) + { + case 4: + do + { dest[9] = dest[6] = dest[3] = dest[0] = r; + dest[10] = dest[7] = dest[4] = dest[1] = g; + dest[11] = dest[8] = dest[5] = dest[2] = b; + inc_ptr(dest, draster); + } + while ( --h ); + break; + case 3: + do + { dest[6] = dest[3] = dest[0] = r; + dest[7] = dest[4] = dest[1] = g; + dest[8] = dest[5] = dest[2] = b; + inc_ptr(dest, draster); + } + while ( --h ); + break; + case 2: + do + { dest[3] = dest[0] = r; + dest[4] = dest[1] = g; + dest[5] = dest[2] = b; + inc_ptr(dest, draster); + } + while ( --h ); + break; + case 1: + do + { dest[0] = r, dest[1] = g, dest[2] = b; + inc_ptr(dest, draster); + } + while ( --h ); + break; + case 0: + default: + ; + } + return 0; +} + +/* Copy a monochrome bitmap. */ +private int +mem_true24_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ const byte *line; + int sbit; + int first_bit; + declare_scan_ptr(dest); + + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base + (sourcex >> 3); + sbit = sourcex & 7; + first_bit = 0x80 >> sbit; + if ( zero != gx_no_color_index ) + { /* Loop for halftones or inverted masks */ + /* (never used). */ + declare_unpack_color(r0, g0, b0, zero); + declare_unpack_color(r1, g1, b1, one); + while ( h-- > 0 ) + { register byte *pptr = dest; + const byte *sptr = line; + register int sbyte = *sptr++; + register int bit = first_bit; + int count = w; + do + { if ( sbyte & bit ) + { if ( one != gx_no_color_index ) + put3(pptr, r1, g1, b1); + } + else + put3(pptr, r0, g0, b0); + pptr += 3; + if ( (bit >>= 1) == 0 ) + bit = 0x80, sbyte = *sptr++; + } + while ( --count > 0 ); + line += sraster; + inc_ptr(dest, draster); + } + } + else if ( one != gx_no_color_index ) + { /* Loop for character and pattern masks. */ + /* This is used heavily. */ + declare_unpack_color(r1, g1, b1, one); + int first_mask = first_bit << 1; + int first_count, first_skip; + if ( sbit + w > 8 ) + first_mask -= 1, + first_count = 8 - sbit; + else + first_mask -= first_mask >> w, + first_count = w; + first_skip = first_count * 3; + while ( h-- > 0 ) + { register byte *pptr = dest; + const byte *sptr = line; + register int sbyte = *sptr++ & first_mask; + int count = w - first_count; + if ( sbyte ) + { register int bit = first_bit; + do + { if ( sbyte & bit ) + put3(pptr, r1, g1, b1); + pptr += 3; + } + while ( (bit >>= 1) & first_mask ); + } + else + pptr += first_skip; + while ( count >= 8 ) + { sbyte = *sptr++; + if ( sbyte & 0xf0 ) + { if ( sbyte & 0x80 ) + put3(pptr, r1, g1, b1); + if ( sbyte & 0x40 ) + put3(pptr + 3, r1, g1, b1); + if ( sbyte & 0x20 ) + put3(pptr + 6, r1, g1, b1); + if ( sbyte & 0x10 ) + put3(pptr + 9, r1, g1, b1); + } + if ( sbyte & 0xf ) + { if ( sbyte & 8 ) + put3(pptr + 12, r1, g1, b1); + if ( sbyte & 4 ) + put3(pptr + 15, r1, g1, b1); + if ( sbyte & 2 ) + put3(pptr + 18, r1, g1, b1); + if ( sbyte & 1 ) + put3(pptr + 21, r1, g1, b1); + } + pptr += 24; + count -= 8; + } + if ( count > 0 ) + { register int bit = 0x80; + sbyte = *sptr++; + do + { if ( sbyte & bit ) + put3(pptr, r1, g1, b1); + pptr += 3; + bit >>= 1; + } + while ( --count > 0 ); + } + line += sraster; + inc_ptr(dest, draster); + } + } + return 0; +} + +/* Copy a color bitmap. */ +private int +mem_true24_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h); + return 0; +} + +/* Copy an alpha map. */ +private int +mem_true24_copy_alpha(gx_device *dev, const byte *base, int sourcex, + int sraster, gx_bitmap_id id, int x, int y, int w, int h, + gx_color_index color, int depth) +{ const byte *line; + declare_scan_ptr(dest); + declare_unpack_color(r, g, b, color); + + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base; + while ( h-- > 0 ) + { register byte *pptr = dest; + int sx; + + for ( sx = sourcex; sx < sourcex + w; ++sx, pptr += 3 ) + { int alpha2, alpha; + + if ( depth == 2 ) /* map 0 - 3 to 0 - 15 */ + alpha = + ((line[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 5; + else + alpha2 = line[sx >> 1], + alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4); + if ( alpha == 15 ) + { /* Just write the new color. */ + put3(pptr, r, g, b); + } + else if ( alpha != 0 ) + { /* Blend RGB values. */ +#define make_shade(old, clr, alpha, amax) \ + (old) + (((int)(clr) - (int)(old)) * (alpha) / (amax)) + pptr[0] = make_shade(pptr[0], r, alpha, 15); + pptr[1] = make_shade(pptr[1], g, alpha, 15); + pptr[2] = make_shade(pptr[2], b, alpha, 15); +#undef make_shade + } + } + line += sraster; + inc_ptr(dest, draster); + } + return 0; +} + +/* ================ "Word"-oriented device ================ */ + +/* Note that on a big-endian machine, this is the same as the */ +/* standard byte-oriented-device. */ + +#if !arch_is_big_endian + +/* Procedures */ +declare_mem_procs(mem24_word_copy_mono, mem24_word_copy_color, mem24_word_fill_rectangle); + +/* Here is the device descriptor. */ +const gx_device_memory far_data mem_true24_word_device = + mem_full_device("image24w", 24, 0, mem_open, + gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb, + mem24_word_copy_mono, mem24_word_copy_color, mem24_word_fill_rectangle, + mem_word_get_bits, gx_default_map_cmyk_color, + gx_default_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Fill a rectangle with a color. */ +private int +mem24_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ byte *base; + uint raster; + fit_fill(dev, x, y, w, h); + base = scan_line_base(mdev, y); + raster = mdev->raster; + mem_swap_byte_rect(base, raster, x * 24, w * 24, h, true); + mem_true24_fill_rectangle(dev, x, y, w, h, color); + mem_swap_byte_rect(base, raster, x * 24, w * 24, h, false); + return 0; +} + +/* Copy a bitmap. */ +private int +mem24_word_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ byte *row; + uint raster; + bool store; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + store = (zero != gx_no_color_index && one != gx_no_color_index); + mem_swap_byte_rect(row, raster, x * 24, w * 24, h, store); + mem_true24_copy_mono(dev, base, sourcex, sraster, id, + x, y, w, h, zero, one); + mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false); + return 0; +} + +/* Copy a color bitmap. */ +private int +mem24_word_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ byte *row; + uint raster; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + mem_swap_byte_rect(row, raster, x * 24, w * 24, h, true); + bytes_copy_rectangle(row + x * 3, raster, base + sourcex * 3, sraster, + w * 3, h); + mem_swap_byte_rect(row, raster, x * 24, w * 24, h, false); + return 0; +} + +#endif /* !arch_is_big_endian */ diff --git a/pstoraster/gdevm32.c b/pstoraster/gdevm32.c new file mode 100644 index 0000000000..2e732915e9 --- /dev/null +++ b/pstoraster/gdevm32.c @@ -0,0 +1,233 @@ +/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevm32.c */ +/* 32-bit-per-pixel "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +/* ================ Standard (byte-oriented) device ================ */ + +#undef chunk +#define chunk byte + +/* Procedures */ +declare_mem_procs(mem_true32_copy_mono, mem_true32_copy_color, mem_true32_fill_rectangle); + +/* The device descriptor. */ +const gx_device_memory far_data mem_true32_device = + mem_full_device("image32", 24, 8, mem_open, + gx_default_map_rgb_color, gx_default_map_color_rgb, + mem_true32_copy_mono, mem_true32_copy_color, mem_true32_fill_rectangle, + mem_get_bits, gx_default_cmyk_map_cmyk_color, + gx_default_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Convert x coordinate to byte offset in scan line. */ +#undef x_to_byte +#define x_to_byte(x) ((x) << 2) + +/* Swap the bytes of a color if needed. */ +#define color_swap_bytes(color)\ + (((color) >> 24) + (((color) >> 8) & 0xff00) +\ + (((color) & 0xff00) << 8) + ((color) << 24)) +#if arch_is_big_endian +# define arrange_bytes(color) (color) +#else +# define arrange_bytes(color) color_swap_bytes(color) +#endif + +/* Fill a rectangle with a color. */ +private int +mem_true32_fill_rectangle(gx_device *dev, + int x, int y, int w, int h, gx_color_index color) +{ bits32 a_color; + declare_scan_ptr(dest); + + fit_fill(dev, x, y, w, h); + a_color = arrange_bytes(color); + setup_rect(dest); + if ( w <= 4 ) + switch ( w ) + { + /*case 0:*/ /* not possible */ +#define dest32 ((bits32 *)dest) + case 1: + do + { dest32[0] = a_color; + inc_ptr(dest, draster); + } + while ( --h > 0 ); + break; + case 2: + do + { dest32[1] = dest32[0] = a_color; + inc_ptr(dest, draster); + } + while ( --h > 0 ); + break; + case 3: + do + { dest32[2] = dest32[1] = dest32[0] = a_color; + inc_ptr(dest, draster); + } + while ( --h > 0 ); + break; + case 4: + do + { dest32[3] = dest32[2] = dest32[1] = dest32[0] = a_color; + inc_ptr(dest, draster); + } + while ( --h > 0 ); + break; + default: /* not possible */ + ; + } + else if ( a_color == 0 ) + do + { memset(dest, 0, w << 2); + inc_ptr(dest, draster); + } + while ( --h > 0 ); + else + do + { bits32 *pptr = dest32; + int cnt = w; + do + { pptr[3] = pptr[2] = pptr[1] = pptr[0] = a_color; + pptr += 4; + } + while ( (cnt -= 4) > 4 ); + do { *pptr++ = a_color; } while ( --cnt > 0 ); + inc_ptr(dest, draster); + } + while ( --h > 0 ); +#undef dest32 + return 0; +} + +/* Copy a monochrome bitmap. */ +private int +mem_true32_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ bits32 a_zero = arrange_bytes(zero); + bits32 a_one = arrange_bytes(one); + const byte *line; + int first_bit; + declare_scan_ptr(dest); + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base + (sourcex >> 3); + first_bit = 0x80 >> (sourcex & 7); + while ( h-- > 0 ) + { register bits32 *pptr = (bits32 *)dest; + const byte *sptr = line; + register int sbyte = *sptr++; + register int bit = first_bit; + int count = w; + do + { if ( sbyte & bit ) + { if ( one != gx_no_color_index ) + *pptr = a_one; + } + else + { if ( zero != gx_no_color_index ) + *pptr = a_zero; + } + if ( (bit >>= 1) == 0 ) + bit = 0x80, sbyte = *sptr++; + pptr++; + } + while ( --count > 0 ); + line += sraster; + inc_ptr(dest, draster); + } + return 0; +} + +/* Copy a color bitmap. */ +private int +mem_true32_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h); + return 0; +} + +/* ================ "Word"-oriented device ================ */ + +/* Note that on a big-endian machine, this is the same as the */ +/* standard byte-oriented-device. */ + +#if !arch_is_big_endian + +/* Procedures */ +declare_mem_procs(mem32_word_copy_mono, mem32_word_copy_color, mem32_word_fill_rectangle); + +/* Here is the device descriptor. */ +const gx_device_memory far_data mem_true32_word_device = + mem_full_device("image32w", 24, 8, mem_open, + gx_default_map_rgb_color, gx_default_map_color_rgb, + mem32_word_copy_mono, mem32_word_copy_color, mem32_word_fill_rectangle, + mem_word_get_bits, gx_default_cmyk_map_cmyk_color, + gx_default_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Fill a rectangle with a color. */ +private int +mem32_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ return mem_true32_fill_rectangle(dev, x, y, w, h, + color_swap_bytes(color)); +} + +/* Copy a bitmap. */ +private int +mem32_word_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ return mem_true32_copy_mono(dev, base, sourcex, sraster, id, + x, y, w, h, color_swap_bytes(zero), + color_swap_bytes(one)); +} + +/* Copy a color bitmap. */ +private int +mem32_word_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ byte *row; + uint raster; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + bytes_copy_rectangle(row + (x << 2), raster, base + (sourcex << 2), + sraster, w << 2, h); + mem_swap_byte_rect(row, raster, x << 5, w << 5, h, false); + return 0; +} + +#endif /* !arch_is_big_endian */ diff --git a/pstoraster/gdevm4.c b/pstoraster/gdevm4.c new file mode 100644 index 0000000000..61b4f637e0 --- /dev/null +++ b/pstoraster/gdevm4.c @@ -0,0 +1,207 @@ +/* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevm4.c */ +/* 4-bit-per-pixel "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +/**************** NOTE: copy_rop only works for gray scale ****************/ +extern dev_proc_strip_copy_rop(mem_gray_strip_copy_rop); + +/* ================ Standard (byte-oriented) device ================ */ + +#undef chunk +#define chunk byte +#define fpat(byt) mono_fill_make_pattern(byt) + +/* Procedures */ +declare_mem_procs(mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle); + +/* The device descriptor. */ +const gx_device_memory far_data mem_mapped4_device = + mem_device("image4", 4, 0, + mem_mapped_map_rgb_color, mem_mapped_map_color_rgb, + mem_mapped4_copy_mono, mem_mapped4_copy_color, mem_mapped4_fill_rectangle, + mem_gray_strip_copy_rop); + +/* Convert x coordinate to byte offset in scan line. */ +#undef x_to_byte +#define x_to_byte(x) ((x) >> 1) + +/* Define the 4-bit fill patterns. */ +static const mono_fill_chunk tile_patterns[16] = + { fpat(0x00), fpat(0x11), fpat(0x22), fpat(0x33), + fpat(0x44), fpat(0x55), fpat(0x66), fpat(0x77), + fpat(0x88), fpat(0x99), fpat(0xaa), fpat(0xbb), + fpat(0xcc), fpat(0xdd), fpat(0xee), fpat(0xff) + }; + + +/* Fill a rectangle with a color. */ +private int +mem_mapped4_fill_rectangle(gx_device *dev, + int x, int y, int w, int h, gx_color_index color) +{ fit_fill(dev, x, y, w, h); + bits_fill_rectangle(scan_line_base(mdev, y), x << 2, mdev->raster, + tile_patterns[color], w << 2, h); + return 0; +} + +/* Copy a bitmap. */ +private int +mem_mapped4_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ const byte *line; + int first_bit; + byte first_mask, b0, b1; + declare_scan_ptr(dest); + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base + (sourcex >> 3); + first_bit = 0x80 >> (sourcex & 7); + first_mask = (x & 1 ? 0xf : 0xf0); + b0 = ((byte)zero << 4) + (byte)zero; + b1 = ((byte)one << 4) + (byte)one; + while ( h-- > 0 ) + { register byte *pptr = (byte *)dest; + const byte *sptr = line; + register int sbyte = *sptr++; + register int bit = first_bit; + register byte mask = first_mask; + int count = w; + do + { if ( sbyte & bit ) + { if ( one != gx_no_color_index ) + *pptr = (*pptr & ~mask) + (b1 & mask); + } + else + { if ( zero != gx_no_color_index ) + *pptr = (*pptr & ~mask) + (b0 & mask); + } + if ( (bit >>= 1) == 0 ) + bit = 0x80, sbyte = *sptr++; + if ( (mask = ~mask) == 0xf0 ) + pptr++; + } + while ( --count > 0 ); + line += sraster; + inc_ptr(dest, draster); + } + return 0; +} + +/* Copy a color bitmap. */ +private int +mem_mapped4_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ int code; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + /* Use monobit copy_mono. */ + /* Patch the width in the device temporarily. */ + dev->width <<= 2; + code = (*dev_proc(&mem_mono_device, copy_mono)) + (dev, base, sourcex << 2, sraster, id, + x << 2, y, w << 2, h, (gx_color_index)0, (gx_color_index)1); + /* Restore the correct width. */ + dev->width >>= 2; + return code; +} + +/* ================ "Word"-oriented device ================ */ + +/* Note that on a big-endian machine, this is the same as the */ +/* standard byte-oriented-device. */ + +#if !arch_is_big_endian + +/* Procedures */ +declare_mem_procs(mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle); + +/* Here is the device descriptor. */ +const gx_device_memory far_data mem_mapped4_word_device = + mem_full_device("image4w", 4, 0, mem_open, + mem_mapped_map_rgb_color, mem_mapped_map_color_rgb, + mem4_word_copy_mono, mem4_word_copy_color, mem4_word_fill_rectangle, + mem_word_get_bits, gx_default_map_cmyk_color, + gx_default_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Fill a rectangle with a color. */ +private int +mem4_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ byte *base; + uint raster; + fit_fill(dev, x, y, w, h); + base = scan_line_base(mdev, y); + raster = mdev->raster; + mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true); + bits_fill_rectangle(base, x << 2, raster, + tile_patterns[color], w << 2, h); + mem_swap_byte_rect(base, raster, x << 2, w << 2, h, true); + return 0; +} + +/* Copy a bitmap. */ +private int +mem4_word_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ byte *row; + uint raster; + bool store; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + store = (zero != gx_no_color_index && one != gx_no_color_index); + mem_swap_byte_rect(row, raster, x << 2, w << 2, h, store); + mem_mapped4_copy_mono(dev, base, sourcex, sraster, id, + x, y, w, h, zero, one); + mem_swap_byte_rect(row, raster, x << 2, w << 2, h, false); + return 0; +} + +/* Copy a color bitmap. */ +private int +mem4_word_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ int code; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + /* Use monobit copy_mono. */ + /* Patch the width in the device temporarily. */ + dev->width <<= 2; + code = (*dev_proc(&mem_mono_word_device, copy_mono)) + (dev, base, sourcex << 2, sraster, id, + x << 2, y, w << 2, h, (gx_color_index)0, (gx_color_index)1); + /* Restore the correct width. */ + dev->width >>= 2; + return code; +} + +#endif /* !arch_is_big_endian */ diff --git a/pstoraster/gdevm8.c b/pstoraster/gdevm8.c new file mode 100644 index 0000000000..e24957d339 --- /dev/null +++ b/pstoraster/gdevm8.c @@ -0,0 +1,225 @@ +/* Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevm8.c */ +/* 8-bit-per-pixel "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +/**************** NOTE: copy_rop only works for gray scale ****************/ +extern dev_proc_strip_copy_rop(mem_gray8_rgb24_strip_copy_rop); /* in gdevmrop.c */ +#define mem_gray8_strip_copy_rop mem_gray8_rgb24_strip_copy_rop + +/* ================ Standard (byte-oriented) device ================ */ + +#undef chunk +#define chunk byte + +/* Procedures */ +declare_mem_procs(mem_mapped8_copy_mono, mem_mapped8_copy_color, mem_mapped8_fill_rectangle); + +/* The device descriptor. */ +const gx_device_memory far_data mem_mapped8_device = + mem_device("image8", 8, 0, + mem_mapped_map_rgb_color, mem_mapped_map_color_rgb, + mem_mapped8_copy_mono, mem_mapped8_copy_color, mem_mapped8_fill_rectangle, + mem_gray8_strip_copy_rop); + +/* Convert x coordinate to byte offset in scan line. */ +#undef x_to_byte +#define x_to_byte(x) (x) + +/* Fill a rectangle with a color. */ +private int +mem_mapped8_fill_rectangle(gx_device *dev, + int x, int y, int w, int h, gx_color_index color) +{ fit_fill(dev, x, y, w, h); + bytes_fill_rectangle(scan_line_base(mdev, y) + x, mdev->raster, + (byte)color, w, h); + return 0; +} + +/* Copy a monochrome bitmap. */ +/* We split up this procedure because of limitations in the bcc32 compiler. */ +private void mapped8_copy01(P9(chunk *, const byte *, int, int, uint, + int, int, byte, byte)); +private void mapped8_copyN1(P8(chunk *, const byte *, int, int, uint, + int, int, byte)); +private void mapped8_copy0N(P8(chunk *, const byte *, int, int, uint, + int, int, byte)); +private int +mem_mapped8_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ const byte *line; + int first_bit; + declare_scan_ptr(dest); + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base + (sourcex >> 3); + first_bit = 0x80 >> (sourcex & 7); +#define is_color(c) ((int)(c) != (int)gx_no_color_index) + if ( is_color(one) ) + { if ( is_color(zero) ) + mapped8_copy01(dest, line, first_bit, sraster, draster, + w, h, (byte)zero, (byte)one); + else + mapped8_copyN1(dest, line, first_bit, sraster, draster, + w, h, (byte)one); + } + else if ( is_color(zero) ) + mapped8_copy0N(dest, line, first_bit, sraster, draster, + w, h, (byte)zero); +#undef is_color + return 0; +} +/* Macros for copy loops */ +#define COPY_BEGIN\ + while ( h-- > 0 )\ + { register byte *pptr = dest;\ + const byte *sptr = line;\ + register int sbyte = *sptr;\ + register uint bit = first_bit;\ + int count = w;\ + do\ + { +#define COPY_END\ + if ( (bit >>= 1) == 0 )\ + bit = 0x80, sbyte = *++sptr;\ + pptr++;\ + }\ + while ( --count > 0 );\ + line += sraster;\ + inc_ptr(dest, draster);\ + } +/* Halftone coloring */ +private void +mapped8_copy01(chunk *dest, const byte *line, int first_bit, + int sraster, uint draster, int w, int h, byte b0, byte b1) +{ COPY_BEGIN + *pptr = (sbyte & bit ? b1 : b0); + COPY_END +} +/* Stenciling */ +private void +mapped8_copyN1(chunk *dest, const byte *line, int first_bit, + int sraster, uint draster, int w, int h, byte b1) +{ COPY_BEGIN + if ( sbyte & bit ) + *pptr = b1; + COPY_END +} +/* Reverse stenciling (probably never used) */ +private void +mapped8_copy0N(chunk *dest, const byte *line, int first_bit, + int sraster, uint draster, int w, int h, byte b0) +{ COPY_BEGIN + if ( !(sbyte & bit) ) + *pptr = b0; + COPY_END +} +#undef COPY_BEGIN +#undef COPY_END + +/* Copy a color bitmap. */ +private int +mem_mapped8_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h); + return 0; +} + +/* ================ "Word"-oriented device ================ */ + +/* Note that on a big-endian machine, this is the same as the */ +/* standard byte-oriented-device. */ + +#if !arch_is_big_endian + +/* Procedures */ +declare_mem_procs(mem8_word_copy_mono, mem8_word_copy_color, mem8_word_fill_rectangle); + +/* Here is the device descriptor. */ +const gx_device_memory far_data mem_mapped8_word_device = + mem_full_device("image8w", 8, 0, mem_open, + mem_mapped_map_rgb_color, mem_mapped_map_color_rgb, + mem8_word_copy_mono, mem8_word_copy_color, mem8_word_fill_rectangle, + mem_word_get_bits, gx_default_map_cmyk_color, + gx_default_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Fill a rectangle with a color. */ +private int +mem8_word_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ byte *base; + uint raster; + fit_fill(dev, x, y, w, h); + base = scan_line_base(mdev, y); + raster = mdev->raster; + mem_swap_byte_rect(base, raster, x << 3, w << 3, h, true); + bytes_fill_rectangle(base + x, raster, (byte)color, w, h); + mem_swap_byte_rect(base, raster, x << 3, w << 3, h, true); + return 0; +} + +/* Copy a bitmap. */ +private int +mem8_word_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ byte *row; + uint raster; + bool store; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + store = (zero != gx_no_color_index && one != gx_no_color_index); + mem_swap_byte_rect(row, raster, x << 3, w << 3, h, store); + mem_mapped8_copy_mono(dev, base, sourcex, sraster, id, + x, y, w, h, zero, one); + mem_swap_byte_rect(row, raster, x << 3, w << 3, h, false); + return 0; +} + +/* Copy a color bitmap. */ +private int +mem8_word_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ byte *row; + uint raster; + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + mem_swap_byte_rect(row, raster, x << 3, w << 3, h, true); + mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h); + mem_swap_byte_rect(row, raster, x << 3, w << 3, h, false); + return 0; +} + +#endif /* !arch_is_big_endian */ diff --git a/pstoraster/gdevmem.c b/pstoraster/gdevmem.c new file mode 100644 index 0000000000..ee5c3d75a2 --- /dev/null +++ b/pstoraster/gdevmem.c @@ -0,0 +1,363 @@ +/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevmem.c */ +/* Generic "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsstruct.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +/* Structure descriptor */ +public_st_device_memory(); + +/* GC procedures */ +#define mptr ((gx_device_memory *)vptr) +private ENUM_PTRS_BEGIN(device_memory_enum_ptrs) { + return (*st_device_forward.enum_ptrs)(vptr, sizeof(gx_device_forward), index-2, pep); + } + case 0: + *pep = (mptr->foreign_bits ? NULL : (void *)mptr->base); + break; + ENUM_STRING_PTR(1, gx_device_memory, palette); +ENUM_PTRS_END +private RELOC_PTRS_BEGIN(device_memory_reloc_ptrs) { + if ( !mptr->foreign_bits ) + { byte *base_old = mptr->base; + long reloc; + int y; + RELOC_PTR(gx_device_memory, base); + reloc = base_old - mptr->base; + for ( y = 0; y < mptr->height; y++ ) + mptr->line_ptrs[y] -= reloc; + /* Relocate line_ptrs, which also points into the data area. */ + mptr->line_ptrs = (byte **)((byte *)mptr->line_ptrs - reloc); + } + RELOC_CONST_STRING_PTR(gx_device_memory, palette); + (*st_device_forward.reloc_ptrs)(vptr, sizeof(gx_device_forward), gcst); +} RELOC_PTRS_END +#undef mptr + +/* Define the palettes for monobit devices. */ +private const byte b_w_palette_string[6] = { 0xff,0xff,0xff, 0,0,0 }; +const gs_const_string mem_mono_b_w_palette = { b_w_palette_string, 6 }; +private const byte w_b_palette_string[6] = { 0,0,0, 0xff,0xff,0xff }; +const gs_const_string mem_mono_w_b_palette = { w_b_palette_string, 6 }; + +/* ------ Generic code ------ */ + +/* Return the appropriate memory device for a given */ +/* number of bits per pixel (0 if none suitable). */ +const gx_device_memory * +gdev_mem_device_for_bits(int bits_per_pixel) +{ switch ( bits_per_pixel ) + { + case 1: return &mem_mono_device; + case 2: return &mem_mapped2_device; + case 4: return &mem_mapped4_device; + case 8: return &mem_mapped8_device; + case 16: return &mem_true16_device; + case 24: return &mem_true24_device; + case 32: return &mem_true32_device; + default: return 0; + } +} +/* Do the same for a word-oriented device. */ +const gx_device_memory * +gdev_mem_word_device_for_bits(int bits_per_pixel) +{ switch ( bits_per_pixel ) + { + case 1: return &mem_mono_word_device; + case 2: return &mem_mapped2_word_device; + case 4: return &mem_mapped4_word_device; + case 8: return &mem_mapped8_word_device; + case 24: return &mem_true24_word_device; + case 32: return &mem_true32_word_device; + default: return 0; + } +} + +/* Make a memory device. */ +/* Note that the default for monobit devices is white = 0, black = 1. */ +void +gs_make_mem_device(gx_device_memory *dev, const gx_device_memory *mdproto, + gs_memory_t *mem, int page_device, gx_device *target) +{ *dev = *mdproto; + dev->memory = mem; + dev->stype = &st_device_memory; + switch ( page_device ) + { + case -1: + dev->std_procs.get_page_device = gx_default_get_page_device; + break; + case 1: + dev->std_procs.get_page_device = gx_page_device_get_page_device; + break; + } + dev->target = target; + if ( target != 0 ) + { /* Forward the color mapping operations to the target. */ + gx_device_forward_color_procs((gx_device_forward *)dev); + } + if ( dev->color_info.depth == 1 ) + gdev_mem_mono_set_inverted(dev, + (target == 0 || + (*dev_proc(target, map_rgb_color)) + (target, (gx_color_value)0, (gx_color_value)0, + (gx_color_value)0) != 0)); +} +/* Make a monobit memory device. This is never a page device. */ +/* Note that white=0, black=1. */ +void +gs_make_mem_mono_device(gx_device_memory *dev, gs_memory_t *mem, + gx_device *target) +{ *dev = mem_mono_device; + dev->memory = mem; + dev->std_procs.get_page_device = gx_default_get_page_device; + mdev->target = target; + gdev_mem_mono_set_inverted(dev, true); +} + + +/* Define whether a monobit memory device is inverted (black=1). */ +void +gdev_mem_mono_set_inverted(gx_device_memory *dev, bool black_is_1) +{ if ( black_is_1 ) + dev->palette = mem_mono_b_w_palette; + else + dev->palette = mem_mono_w_b_palette; +} + +/* Compute the size of the bitmap storage, */ +/* including the space for the scan line pointer table. */ +/* Note that scan lines are padded to a multiple of align_bitmap_mod bytes, */ +/* and additional padding may be needed if the pointer table */ +/* must be aligned to an even larger modulus. */ +private ulong +mem_bitmap_bits_size(const gx_device_memory *dev) +{ return round_up((ulong)dev->height * gdev_mem_raster(dev), + max(align_bitmap_mod, arch_align_ptr_mod)); +} +ulong +gdev_mem_bitmap_size(const gx_device_memory *dev) +{ return mem_bitmap_bits_size(dev) + + (ulong)dev->height * sizeof(byte *); +} + +/* Open a memory device, allocating the data area if appropriate, */ +/* and create the scan line table. */ +private void mem_set_line_ptrs(P3(gx_device_memory *, byte **, byte *)); +int +mem_open(gx_device *dev) +{ if ( mdev->bitmap_memory != 0 ) + { /* Allocate the data now. */ + ulong size = gdev_mem_bitmap_size(mdev); + if ( (uint)size != size ) + return_error(gs_error_limitcheck); + mdev->base = gs_alloc_bytes(mdev->bitmap_memory, (uint)size, + "mem_open"); + if ( mdev->base == 0 ) + return_error(gs_error_VMerror); + mdev->foreign_bits = false; + } +/* + * Macro for adding an offset to a pointer when setting up the + * scan line table. This isn't just pointer arithmetic, because of + * the segmenting considerations discussed in gdevmem.h. + */ +#define huge_ptr_add(base, offset)\ + ((void *)((byte huge *)(base) + (offset))) + mem_set_line_ptrs(mdev, + huge_ptr_add(mdev->base, + mem_bitmap_bits_size(mdev)), + mdev->base); + return 0; +} +/* Set up the scan line pointers of a memory device. */ +/* Sets line_ptrs, base, raster; uses width, height, color_info.depth. */ +private void +mem_set_line_ptrs(gx_device_memory *devm, byte **line_ptrs, byte *base) +{ byte **pptr = devm->line_ptrs = line_ptrs; + byte **pend = pptr + devm->height; + byte *scan_line = devm->base = base; + uint raster = devm->raster = gdev_mem_raster(devm); + + while ( pptr < pend ) + { *pptr++ = scan_line; + scan_line = huge_ptr_add(scan_line, raster); + } +} + +/* Return the initial transformation matrix */ +void +mem_get_initial_matrix(gx_device *dev, gs_matrix *pmat) +{ pmat->xx = mdev->initial_matrix.xx; + pmat->xy = mdev->initial_matrix.xy; + pmat->yx = mdev->initial_matrix.yx; + pmat->yy = mdev->initial_matrix.yy; + pmat->tx = mdev->initial_matrix.tx; + pmat->ty = mdev->initial_matrix.ty; +} + +/* Test whether a device is a memory device */ +bool +gs_device_is_memory(const gx_device *dev) +{ /* We can't just compare the procs, or even an individual proc, */ + /* because we might be tracing. Instead, check the identity of */ + /* the device name. */ + const gx_device_memory *bdev = + gdev_mem_device_for_bits(dev->color_info.depth); + if ( bdev != 0 && bdev->dname == dev->dname ) + return true; + bdev = gdev_mem_word_device_for_bits(dev->color_info.depth); + return (bdev != 0 && bdev->dname == dev->dname); +} + +/* Close a memory device, freeing the data area if appropriate. */ +int +mem_close(gx_device *dev) +{ if ( mdev->bitmap_memory != 0 ) + gs_free_object(mdev->bitmap_memory, mdev->base, "mem_close"); + return 0; +} + +/* Copy a scan line to a client. */ +#undef chunk +#define chunk byte +int +mem_get_bits(gx_device *dev, int y, byte *str, byte **actual_data) +{ byte *src; + if ( y < 0 || y >= dev->height ) + return_error(gs_error_rangecheck); + src = scan_line_base(mdev, y); + if ( actual_data == 0 ) + memcpy(str, src, gx_device_raster(dev, 0)); + else + *actual_data = src; + return 0; +} + +#if !arch_is_big_endian + +/* Swap byte order in a rectangular subset of a bitmap. */ +/* If store = true, assume the rectangle will be overwritten, */ +/* so don't swap any bytes where it doesn't matter. */ +/* The caller has already done a fit_fill or fit_copy. */ +void +mem_swap_byte_rect(byte *base, uint raster, int x, int w, int h, bool store) +{ int xbit = x & 31; + if ( store ) + { if ( xbit + w > 64 ) + { /* Operation spans multiple words. */ + /* Just swap the words at the left and right edges. */ + if ( xbit != 0 ) + mem_swap_byte_rect(base, raster, x, 1, h, false); + x += w - 1; + xbit = x & 31; + if ( xbit == 31 ) + return; + w = 1; + } + } + /* Swap the entire rectangle (or what's left of it). */ + { byte *row = base + ((x >> 5) << 2); + int nw = (xbit + w + 31) >> 5; + int ny; + for ( ny = h; ny > 0; row += raster, --ny ) + { int nx = nw; + bits32 *pw = (bits32 *)row; + do + { bits32 w = *pw; + *pw++ = (w >> 24) + ((w >> 8) & 0xff00) + + ((w & 0xff00) << 8) + (w << 24); + } + while ( --nx); + } + } +} + +/* Copy a word-oriented scan line to the client, swapping bytes as needed. */ +int +mem_word_get_bits(gx_device *dev, int y, byte *str, byte **actual_data) +{ byte *src; + uint raster = gx_device_raster(dev, 0); /* only doing 1 scan line */ + if ( y < 0 || y >= dev->height ) + return_error(gs_error_rangecheck); + src = scan_line_base(mdev, y); + /* We use raster << 3 rather than dev->width so that */ + /* the right thing will happen if depth > 1. */ + mem_swap_byte_rect(src, raster, 0, raster << 3, 1, false); + memcpy(str, src, raster); + if ( actual_data != 0 ) + *actual_data = str; + mem_swap_byte_rect(src, raster, 0, raster << 3, 1, false); + return 0; +} + +#endif /* !arch_is_big_endian */ + +/* Map a r-g-b color to a color index for a mapped color memory device */ +/* (2, 4, or 8 bits per pixel.) */ +/* This requires searching the palette. */ +gx_color_index +mem_mapped_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g, + gx_color_value b) +{ byte br = gx_color_value_to_byte(r); + byte bg = gx_color_value_to_byte(g); + byte bb = gx_color_value_to_byte(b); + register const byte *pptr = mdev->palette.data; + int cnt = mdev->palette.size; + const byte *which = 0; /* initialized only to pacify gcc */ + int best = 256*3; + + while ( (cnt -= 3) >= 0 ) + { register int diff = *pptr - br; + if ( diff < 0 ) diff = -diff; + if ( diff < best ) /* quick rejection */ + { int dg = pptr[1] - bg; + if ( dg < 0 ) dg = -dg; + if ( (diff += dg) < best ) /* quick rejection */ + { int db = pptr[2] - bb; + if ( db < 0 ) db = -db; + if ( (diff += db) < best ) + which = pptr, best = diff; + } + } + pptr += 3; + } + return (gx_color_index)((which - mdev->palette.data) / 3); +} + +/* Map a color index to a r-g-b color for a mapped color memory device. */ +int +mem_mapped_map_color_rgb(gx_device *dev, gx_color_index color, + gx_color_value prgb[3]) +{ const byte *pptr = mdev->palette.data + (int)color * 3; + prgb[0] = gx_color_value_from_byte(pptr[0]); + prgb[1] = gx_color_value_from_byte(pptr[1]); + prgb[2] = gx_color_value_from_byte(pptr[2]); + return 0; +} diff --git a/pstoraster/gdevmem.h b/pstoraster/gdevmem.h new file mode 100644 index 0000000000..02db913798 --- /dev/null +++ b/pstoraster/gdevmem.h @@ -0,0 +1,217 @@ +/* Copyright (C) 1991, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevmem.h */ +/* Private definitions for memory devices. */ + +#include "gsbitops.h" + +/* + The representation for a "memory" device is simply a + contiguous bitmap stored in something like the PostScript + representation, i.e., each scan line (in left-to-right order), padded + to a multiple of bitmap_align_mod bytes, followed immediately by + the next one. + + The representation of strings in the interpreter limits + the size of a string to 64K-1 bytes, which means we can't simply use + a string for the contents of a memory device. + We get around this problem by making the client read out the + contents of a memory device bitmap in pieces. + + On 80x86 PCs running in 16-bit mode, there may be no way to + obtain a contiguous block of storage larger than 64K bytes, + which typically isn't big enough for a full-screen bitmap. + We take the following compromise position: if the PC is running in + native mode (pseudo-segmenting), we limit the bitmap to 64K; + if the PC is running in protected mode (e.g., under MS Windows), + we assume that blocks larger than 64K have sequential segment numbers, + and that the client arranges things so that an individual scan line, + the scan line pointer table, and any single call on a drawing routine + do not cross a segment boundary. + + Even though the scan lines are stored contiguously, we store a table + of their base addresses, because indexing into it is faster than + the multiplication that would otherwise be needed. +*/ + +/* + * Macros for scan line access. + * x_to_byte is different for each number of bits per pixel. + * Note that these macros depend on the definition of chunk: + * each procedure that uses the scanning macros should #define + * (not typedef) chunk as either uint or byte. + */ +#define declare_scan_ptr(ptr) declare_scan_ptr_as(ptr, chunk *) +#define declare_scan_ptr_as(ptr,ptype)\ + register ptype ptr; uint draster +#define setup_rect(ptr) setup_rect_as(ptr, chunk *) +#define setup_rect_as(ptr,ptype)\ + draster = mdev->raster;\ + ptr = (ptype)(scan_line_base(mdev, y) +\ + (x_to_byte(x) & -chunk_align_bytes)) + +/* ------ Generic macros ------ */ + +/* Macro for declaring the essential device procedures. */ +dev_proc_get_initial_matrix(mem_get_initial_matrix); +dev_proc_close_device(mem_close); +#define declare_mem_map_procs(map_rgb_color, map_color_rgb)\ + private dev_proc_map_rgb_color(map_rgb_color);\ + private dev_proc_map_color_rgb(map_color_rgb) +#define declare_mem_procs(copy_mono, copy_color, fill_rectangle)\ + private dev_proc_copy_mono(copy_mono);\ + private dev_proc_copy_color(copy_color);\ + private dev_proc_fill_rectangle(fill_rectangle) + +/* The following are used for all except planar or word-oriented devices. */ +dev_proc_open_device(mem_open); +dev_proc_get_bits(mem_get_bits); +/* The following are for word-oriented devices. */ +#if arch_is_big_endian +# define mem_word_get_bits mem_get_bits +#else +dev_proc_get_bits(mem_word_get_bits); +#endif +/* The following are used for the non-true-color devices. */ +dev_proc_map_rgb_color(mem_mapped_map_rgb_color); +dev_proc_map_color_rgb(mem_mapped_map_color_rgb); + +/* + * Macro for generating the device descriptor. + * Various compilers have problems with the obvious definition + * for max_value, namely: + * (depth >= 8 ? 255 : (1 << depth) - 1) + * I tried changing (1 << depth) to (1 << (depth & 15)) to forestall bogus + * error messages about invalid shift counts, but the H-P compiler chokes + * on this. Since the only values of depth we ever plan to support are + * powers of 2 (and 24), we just go ahead and enumerate them. + */ +#define max_value_gray(rgb_depth, gray_depth)\ + (gray_depth ? (1 << gray_depth) - 1 : max_value_rgb(rgb_depth, 0)) +#define max_value_rgb(rgb_depth, gray_depth)\ + (rgb_depth >= 8 ? 255 : rgb_depth == 4 ? 15 : rgb_depth == 2 ? 3 :\ + rgb_depth == 1 ? 1 : (1 << gray_depth) - 1) +#define mem_full_alpha_device(name, rgb_depth, gray_depth, open, map_rgb_color, map_color_rgb, copy_mono, copy_color, fill_rectangle, get_bits, map_cmyk_color, copy_alpha, strip_tile_rectangle, strip_copy_rop)\ +{ std_device_dci_body(gx_device_memory, 0, name,\ + 0, 0, 72, 72,\ + (rgb_depth ? 3 : 0) + (gray_depth ? 1 : 0), /* num_components */\ + rgb_depth + gray_depth, /* depth */\ + max_value_gray(rgb_depth, gray_depth), /* max_gray */\ + max_value_rgb(rgb_depth, gray_depth), /* max_color */\ + max_value_gray(rgb_depth, gray_depth) + 1, /* dither_grays */\ + max_value_rgb(rgb_depth, gray_depth) + 1 /* dither_colors */\ + ),\ + { open, /* differs */\ + mem_get_initial_matrix,\ + gx_default_sync_output,\ + gx_default_output_page,\ + mem_close,\ + map_rgb_color, /* differs */\ + map_color_rgb, /* differs */\ + fill_rectangle, /* differs */\ + gx_default_tile_rectangle,\ + copy_mono, /* differs */\ + copy_color, /* differs */\ + gx_default_draw_line,\ + get_bits, /* differs */\ + gx_default_get_params,\ + gx_default_put_params,\ + map_cmyk_color, /* differs */\ + gx_forward_get_xfont_procs,\ + gx_forward_get_xfont_device,\ + gx_default_map_rgb_alpha_color,\ + gx_forward_get_page_device,\ + gx_default_get_alpha_bits, /* default is no alpha */\ + copy_alpha, /* differs */\ + gx_default_get_band,\ + gx_default_copy_rop,\ + gx_default_fill_path,\ + gx_default_stroke_path,\ + gx_default_fill_mask,\ + gx_default_fill_trapezoid,\ + gx_default_fill_parallelogram,\ + gx_default_fill_triangle,\ + gx_default_draw_thin_line,\ + gx_default_begin_image,\ + gx_default_image_data,\ + gx_default_end_image,\ + strip_tile_rectangle, /* differs */\ + strip_copy_rop /* differs */\ + },\ + 0, /* target */\ + mem_device_init_private /* see gxdevmem.h */\ +} +#define mem_full_device(name, rgb_depth, gray_depth, open, map_rgb_color, map_color_rgb, copy_mono, copy_color, fill_rectangle, get_bits, map_cmyk_color, strip_tile_rectangle, strip_copy_rop)\ + mem_full_alpha_device(name, rgb_depth, gray_depth, open, map_rgb_color,\ + map_color_rgb, copy_mono, copy_color, fill_rectangle,\ + get_bits, map_cmyk_color, gx_default_copy_alpha,\ + strip_tile_rectangle, strip_copy_rop) +#define mem_device(name, rgb_depth, gray_depth, map_rgb_color, map_color_rgb, copy_mono, copy_color, fill_rectangle, strip_copy_rop)\ + mem_full_device(name, rgb_depth, gray_depth, mem_open, map_rgb_color,\ + map_color_rgb, copy_mono, copy_color, fill_rectangle,\ + mem_get_bits, gx_default_map_cmyk_color,\ + gx_default_strip_tile_rectangle, strip_copy_rop) + +/* Swap a rectangle of bytes, for converting between word- and */ +/* byte-oriented representation. */ +void mem_swap_byte_rect(P6(byte *, uint, int, int, int, bool)); + +/* Copy a rectangle of bytes from a source to a destination. */ +#define mem_copy_byte_rect(mdev, base, sourcex, sraster, x, y, w, h)\ + bytes_copy_rectangle(scan_line_base(mdev, y) + x_to_byte(x),\ + (mdev)->raster,\ + base + x_to_byte(sourcex), sraster,\ + x_to_byte(w), h) + +/* Macro for casting gx_device argument */ +#define mdev ((gx_device_memory *)dev) + +/* ------ Implementations ------ */ + +extern const gx_device_memory far_data mem_mono_device; +extern const gx_device_memory far_data mem_mapped2_device; +extern const gx_device_memory far_data mem_mapped4_device; +extern const gx_device_memory far_data mem_mapped8_device; +extern const gx_device_memory far_data mem_true16_device; +extern const gx_device_memory far_data mem_true24_device; +extern const gx_device_memory far_data mem_true32_device; +extern const gx_device_memory far_data mem_planar_device; +#if arch_is_big_endian +# define mem_mono_word_device mem_mono_device +# define mem_mapped2_word_device mem_mapped2_device +# define mem_mapped4_word_device mem_mapped4_device +# define mem_mapped8_word_device mem_mapped8_device +# define mem_true24_word_device mem_true24_device +# define mem_true32_word_device mem_true32_device +#else +extern const gx_device_memory far_data mem_mono_word_device; +extern const gx_device_memory far_data mem_mapped2_word_device; +extern const gx_device_memory far_data mem_mapped4_word_device; +extern const gx_device_memory far_data mem_mapped8_word_device; +extern const gx_device_memory far_data mem_true24_word_device; +extern const gx_device_memory far_data mem_true32_word_device; +#endif +/* Provide standard palettes for 1-bit devices. */ +extern const gs_const_string mem_mono_b_w_palette; /* black=1, white=0 */ +extern const gs_const_string mem_mono_w_b_palette; /* black=0, white=1 */ diff --git a/pstoraster/gdevmpla.c b/pstoraster/gdevmpla.c new file mode 100644 index 0000000000..66df9173c8 --- /dev/null +++ b/pstoraster/gdevmpla.c @@ -0,0 +1,182 @@ +/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevmpla.c */ +/* Any-depth planar "memory" (stored bitmap) devices */ +#include "memory_.h" +#include "gx.h" +#include "gxdevice.h" +#include "gxdevmem.h" /* semi-public definitions */ +#include "gdevmem.h" /* private definitions */ + +/* + * Planar memory devices store the bits by planes instead of by chunks. + * The plane corresponding to the least significant bit of the color index + * is stored first. + * + * The current implementations are quite inefficient. + * We may improve them someday if anyone cares. + */ + +/* Procedures */ +declare_mem_map_procs(mem_planar_map_rgb_color, mem_planar_map_color_rgb); +declare_mem_procs(mem_planar_copy_mono, mem_planar_copy_color, mem_planar_fill_rectangle); + +/* The device descriptor. */ +/* The instance is public. */ +/* The default instance has depth = 1, but clients may set this */ +/* to other values before opening the device. */ +private dev_proc_open_device(mem_planar_open); +private dev_proc_get_bits(mem_planar_get_bits); +const gx_device_memory far_data mem_planar_device = + mem_full_device("image(planar)", 0, 1, mem_planar_open, + mem_planar_map_rgb_color, mem_planar_map_color_rgb, + mem_planar_copy_mono, mem_planar_copy_color, mem_planar_fill_rectangle, + mem_planar_get_bits, gx_default_map_cmyk_color, + gx_default_strip_tile_rectangle, gx_no_strip_copy_rop); + +/* Open a planar memory device. */ +private int +mem_planar_open(gx_device *dev) +{ /* Temporarily reset the parameters, and call */ + /* the generic open procedure. */ + int depth = dev->color_info.depth; + int height = dev->height; + int code; + + dev->height *= depth; + dev->color_info.depth = 1; + code = mem_open(dev); + dev->height = height; + dev->color_info.depth = depth; + return code; +} + +/* Map a r-g-b color to a color index. */ +private gx_color_index +mem_planar_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g, + gx_color_value b) +{ int depth = dev->color_info.depth; + return (*dev_proc(gdev_mem_device_for_bits(depth), map_rgb_color)) + (dev, r, g, b); +} + +/* Map a color index to a r-g-b color. */ +private int +mem_planar_map_color_rgb(gx_device *dev, gx_color_index color, + gx_color_value prgb[3]) +{ int depth = dev->color_info.depth; + return (*dev_proc(gdev_mem_device_for_bits(depth), map_color_rgb)) + (dev, color, prgb); +} + +/* Fill a rectangle with a color. */ +private int +mem_planar_fill_rectangle(gx_device *dev, + int x, int y, int w, int h, gx_color_index color) +{ byte **ptrs = mdev->line_ptrs; + int i; + for ( i = 0; i < dev->color_info.depth; + i++, mdev->line_ptrs += dev->height + ) + (*dev_proc(&mem_mono_device, fill_rectangle))(dev, + x, y, w, h, (color >> i) & 1); + mdev->line_ptrs = ptrs; + return 0; +} + +/* Copy a bitmap. */ +private int +mem_planar_copy_mono(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index zero, gx_color_index one) +{ byte **ptrs = mdev->line_ptrs; + int i; + for ( i = 0; i < dev->color_info.depth; + i++, mdev->line_ptrs += dev->height + ) + (*dev_proc(&mem_mono_device, copy_mono))(dev, + base, sourcex, sraster, id, x, y, w, h, + (zero == gx_no_color_index ? gx_no_color_index : + (zero >> i) & 1), + (one == gx_no_color_index ? gx_no_color_index : + (one >> i) & 1)); + mdev->line_ptrs = ptrs; + return 0; +} + +/* Copy a color bitmap. */ +/* This is very slow and messy. */ +private int +mem_planar_copy_color(gx_device *dev, + const byte *base, int sourcex, int sraster, gx_bitmap_id id, + int x, int y, int w, int h) +{ byte **ptrs = mdev->line_ptrs; + int depth = dev->color_info.depth; + int wleft = w; + int hleft = h; + const byte *srow = base; + int ynext = y; +#define max_w 32 + union _b { + long l[max_w / sizeof(long)]; + byte b[max_w / 8]; + } buf; + + while ( wleft > max_w ) + { mem_planar_copy_color(dev, base, + sourcex + wleft - max_w, sraster, gx_no_bitmap_id, + x + wleft - max_w, y, max_w, h); + wleft -= max_w; + } + for ( ; hleft > 0; + srow += sraster, ynext++, hleft--, + mdev->line_ptrs += dev->height + ) + { int i; + for ( i = 0; i < depth; + i++, mdev->line_ptrs += dev->height + ) + { int sx, bx; + memset(buf.b, 0, sizeof(buf.b)); + for ( sx = 0, bx = sourcex * depth + depth - 1 - i; + sx < w; sx++, bx += depth + ) + if ( srow[bx >> 3] & (0x80 >> (bx & 7)) ) + buf.b[sx >> 3] |= 0x80 >> (sx & 7); + (*dev_proc(&mem_mono_device, copy_mono))(dev, + buf.b, 0, sizeof(buf), gx_no_bitmap_id, + x, ynext, w, 1, + (gx_color_index)0, (gx_color_index)1); + } + mdev->line_ptrs = ptrs; + } + return 0; +} + +/* Copy bits back from a planar memory device. */ +/****** NOT IMPLEMENTED YET ******/ +private int +mem_planar_get_bits(gx_device *dev, int y, byte *str, byte **actual_data) +{ return -1; +} diff --git a/pstoraster/gdevmrop.c b/pstoraster/gdevmrop.c new file mode 100644 index 0000000000..b9a0c1b57c --- /dev/null +++ b/pstoraster/gdevmrop.c @@ -0,0 +1,1013 @@ +/* Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevmrop.c */ +/* RasterOp / transparency / render algorithm implementation for */ +/* memory devices */ +#include "memory_.h" +#include "gx.h" +#include "gsbittab.h" +#include "gserrors.h" +#include "gsropt.h" +#include "gxdcolor.h" +#include "gxdevice.h" +#include "gxdevmem.h" +#include "gxdevrop.h" +#include "gdevmrop.h" + +#define mdev ((gx_device_memory *)dev) + +/**************** NOTE: **************** + * The 2- and 4-bit cases don't handle transparency right. + * The 8- and 24-bit cases haven't been tested. + * The 16- and 32-bit cases aren't implemented. + ***************** ****************/ + +/* Forward references */ +private gs_rop3_t gs_transparent_rop(P3(gs_rop3_t rop, bool source_transparent, + bool pattern_transparent)); + +#define chunk byte + +/* Calculate the X offset for a given Y value, */ +/* taking shift into account if necessary. */ +#define x_offset(px, ty, textures)\ + ((textures)->shift == 0 ? (px) :\ + (px) + (ty) / (textures)->rep_height * (textures)->rep_shift) + +/* ---------------- Initialization ---------------- */ + +void +gs_roplib_init(gs_memory_t *mem) +{ /* Replace the default and forwarding copy_rop procedures. */ + gx_default_copy_rop_proc = gx_real_default_copy_rop; + gx_forward_copy_rop_proc = gx_forward_copy_rop; + gx_default_strip_copy_rop_proc = gx_real_default_strip_copy_rop; + gx_forward_strip_copy_rop_proc = gx_forward_strip_copy_rop; +} + +/* ---------------- Debugging aids ---------------- */ + +#ifdef DEBUG + +private void +trace_copy_rop(const char *cname, gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ dprintf4("%s: dev=0x%lx(%s) depth=%d\n", + cname, (ulong)dev, dev->dname, dev->color_info.depth); + dprintf4(" source data=0x%lx x=%d raster=%u id=%lu colors=", + (ulong)sdata, sourcex, sraster, (ulong)id); + if ( scolors ) + dprintf2("(%lu,%lu);\n", scolors[0], scolors[1]); + else + dputs("none;\n"); + if ( textures ) + dprintf8(" textures=0x%lx size=%dx%d(%dx%d) raster=%u shift=%d(%d)", + (ulong)textures, textures->size.x, textures->size.y, + textures->rep_width, textures->rep_height, textures->raster, + textures->shift, textures->rep_shift); + else + dputs(" textures=none"); + if ( tcolors ) + dprintf2(" colors=(%lu,%lu)\n", tcolors[0], tcolors[1]); + else + dputs(" colors=none\n"); + dprintf7(" rect=(%d,%d),(%d,%d) phase=(%d,%d) op=0x%x\n", + x, y, x + width, y + height, phase_x, phase_y, + (uint)lop); + if ( gs_debug_c('B') ) + { if ( sdata ) + debug_dump_bitmap(sdata, sraster, height, "source bits"); + if ( textures && textures->data ) + debug_dump_bitmap(textures->data, textures->raster, + textures->size.y, "textures bits"); + } +} + +#endif + +/* ---------------- Monobit RasterOp ---------------- */ + +int +mem_mono_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ gs_rop3_t rop = (gs_rop3_t)(lop & lop_rop_mask); + gx_strip_bitmap no_texture; + bool invert; + uint draster = mdev->raster; + uint traster; + int line_count; + byte *drow; + const byte *srow; + int ty; + + /* If map_rgb_color isn't the default one for monobit memory */ + /* devices, palette might not be set; set it now if needed. */ + if ( mdev->palette.data == 0 ) + gdev_mem_mono_set_inverted(mdev, + (*dev_proc(dev, map_rgb_color)) + (dev, (gx_color_value)0, + (gx_color_value)0, (gx_color_value)0) + != 0); + invert = mdev->palette.data[0] != 0; + +#ifdef DEBUG + if ( gs_debug_c('b') ) + trace_copy_rop("mem_mono_strip_copy_rop", + dev, sdata, sourcex, sraster, + id, scolors, textures, tcolors, + x, y, width, height, phase_x, phase_y, lop); + if ( gs_debug_c('B') ) + debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster, + height, "initial dest bits"); +#endif + + /* Handle source and destination transparency. */ + rop = gs_transparent_rop(rop, lop & lop_S_transparent, + lop & lop_T_transparent); + + /* + * RasterOp is defined as operating in RGB space; in the monobit + * case, this means black = 0, white = 1. However, most monobit + * devices use the opposite convention. To make this work, + * we must precondition the Boolean operation by swapping the + * order of bits end-for-end and then inverting. + */ + + if ( invert ) + rop = (gs_rop3_t)(byte_reverse_bits[rop] ^ 0xff); + + /* Modify the raster operation according to the source palette. */ + if ( scolors != 0 ) + { /* Source with palette. */ + switch ( (int)((scolors[1] << 1) + scolors[0]) ) + { + case 0: rop = (gs_rop3_t)rop3_know_S_0(rop); break; + case 1: rop = (gs_rop3_t)rop3_invert_S(rop); break; + case 2: break; + case 3: rop = (gs_rop3_t)rop3_know_S_1(rop); break; + } + } + + /* Modify the raster operation according to the texture palette. */ + if ( tcolors != 0 ) + { /* Texture with palette. */ + switch ( (int)((tcolors[1] << 1) + tcolors[0]) ) + { + case 0: rop = (gs_rop3_t)rop3_know_T_0(rop); break; + case 1: rop = (gs_rop3_t)rop3_invert_T(rop); break; + case 2: break; + case 3: rop = (gs_rop3_t)rop3_know_T_1(rop); break; + } + } + + /* Handle constant source and/or texture. */ + if ( rop3_uses_S(rop) ) + { fit_copy(dev, sdata, sourcex, sraster, id, + x, y, width, height); + } + else + { /* Source is not used; sdata et al may be garbage. */ + sdata = mdev->base; /* arbitrary, as long as all */ + /* accesses are valid */ + sourcex = x; /* guarantee no source skew */ + sraster = 0; + fit_fill(dev, x, y, width, height); + } + if ( !rop3_uses_T(rop) ) + { /* Texture is not used; texture may be garbage. */ + no_texture.data = mdev->base; /* arbitrary */ + no_texture.raster = 0; + no_texture.size.x = width; + no_texture.size.y = height; + no_texture.rep_width = no_texture.rep_height = 1; + no_texture.rep_shift = no_texture.shift = 0; + textures = &no_texture; + } + +#ifdef DEBUG + if_debug1('b', "final rop=0x%x\n", rop); +#endif + + /* Set up transfer parameters. */ + line_count = height; + srow = sdata; + drow = scan_line_base(mdev, y); + traster = textures->raster; + ty = y + phase_y; + + /* Loop over scan lines. */ + for ( ; line_count-- > 0; drow += draster, srow += sraster, ++ty ) + { /* Loop over copies of the tile. */ + int sx = sourcex; + int dx = x; + int w = width; + const byte *trow = + textures->data + (ty % textures->size.y) * traster; + int xoff = x_offset(phase_x, ty, textures); + int nw; + + for ( ; w > 0; sx += nw, dx += nw, w -= nw ) + { int dbit = dx & 7; + int sbit = sx & 7; + int sskew = sbit - dbit; + int tx = (dx + xoff) % textures->rep_width; + int tbit = tx & 7; + int tskew = tbit - dbit; + int left = nw = min(w, textures->size.x - tx); + byte lmask = 0xff >> dbit; + byte rmask = 0xff << (~(dbit + nw - 1) & 7); + byte mask = lmask; + int nx = 8 - dbit; + byte *dptr = drow + (dx >> 3); + const byte *sptr = srow + (sx >> 3); + const byte *tptr = trow + (tx >> 3); + + if ( sskew < 0 ) + --sptr, sskew += 8; + if ( tskew < 0 ) + --tptr, tskew += 8; + for ( ; left > 0; + left -= nx, mask = 0xff, nx = 8, + ++dptr, ++sptr, ++tptr + ) + { byte dbyte = *dptr; +#define fetch1(ptr, skew)\ + (skew ? (ptr[0] << skew) + (ptr[1] >> (8 - skew)) : *ptr) + byte sbyte = fetch1(sptr, sskew); + byte tbyte = fetch1(tptr, tskew); +#undef fetch1 + byte result = + (*rop_proc_tab[rop])(dbyte, sbyte, tbyte); + if ( left <= nx ) + mask &= rmask; + *dptr = (mask == 0xff ? result : + (result & mask) | (dbyte & ~mask)); + } + } + } +#ifdef DEBUG + if ( gs_debug_c('B') ) + debug_dump_bitmap(scan_line_base(mdev, y), mdev->raster, + height, "final dest bits"); +#endif + return 0; +} + +/* ---------------- Fake RasterOp for 2- and 4-bit devices ---------------- */ + +int +mem_gray_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ gx_color_index scolors2[2]; + const gx_color_index *real_scolors = scolors; + gx_color_index tcolors2[2]; + const gx_color_index *real_tcolors = tcolors; + gx_strip_bitmap texture2; + const gx_strip_bitmap *real_texture = textures; + long tdata; + int depth = dev->color_info.depth; + int log2_depth = depth >> 1; /* works for 2, 4 */ + gx_color_index max_pixel = (1 << depth) - 1; + int code; + +#ifdef DEBUG + if ( gs_debug_c('b') ) + trace_copy_rop("mem_gray_strip_copy_rop", + dev, sdata, sourcex, sraster, + id, scolors, textures, tcolors, + x, y, width, height, phase_x, phase_y, lop); +#endif + if ( scolors ) + { /* We can't handle "real" source colors. */ + if ( (scolors[0] | scolors[1]) & ~max_pixel ) + return_error(gs_error_rangecheck); + scolors2[0] = scolors[0] & 1; + scolors2[1] = scolors[1] & 1; + real_scolors = scolors2; + } + if ( textures ) + { texture2 = *textures; + texture2.size.x <<= log2_depth; + texture2.rep_width <<= log2_depth; + texture2.shift <<= log2_depth; + texture2.rep_shift <<= log2_depth; + real_texture = &texture2; + } + if ( tcolors ) + { /* We can't handle monobit textures. */ + if ( tcolors[0] != tcolors[1] ) + return_error(gs_error_rangecheck); + /* For polybit textures with colors other than */ + /* all 0s or all 1s, fabricate the data. */ + if ( tcolors[0] != 0 && tcolors[0] != max_pixel ) + { real_tcolors = 0; + *(byte *)&tdata = (byte)tcolors[0] << (8 - depth); + texture2.data = (byte *)&tdata; + texture2.raster = align_bitmap_mod; + texture2.size.x = texture2.rep_width = depth; + texture2.size.y = texture2.rep_height = 1; + texture2.id = gx_no_bitmap_id; + texture2.shift = texture2.rep_shift = 0; + real_texture = &texture2; + } + else + { tcolors2[0] = tcolors2[1] = tcolors[0] & 1; + real_tcolors = tcolors2; + } + } + dev->width <<= log2_depth; + code = mem_mono_strip_copy_rop(dev, sdata, + (real_scolors == NULL ? sourcex << log2_depth : sourcex), + sraster, id, real_scolors, real_texture, real_tcolors, + x << log2_depth, y, width << log2_depth, height, + phase_x << log2_depth, phase_y, lop); + dev->width >>= log2_depth; + return code; +} + +/* ---------------- RasterOp with 8-bit gray / 24-bit RGB ---------------- */ + +int +mem_gray8_rgb24_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ gs_rop3_t rop = (gs_rop3_t)(lop & lop_rop_mask); + gx_color_index const_source = gx_no_color_index; + gx_color_index const_texture = gx_no_color_index; + uint draster = mdev->raster; + int line_count; + byte *drow; + int depth = dev->color_info.depth; + int bpp = depth >> 3; /* bytes per pixel, 1 or 3 */ + gx_color_index all_ones = ((gx_color_index)1 << depth) - 1; + gx_color_index strans = + (lop & lop_S_transparent ? all_ones : gx_no_color_index); + gx_color_index ttrans = + (lop & lop_T_transparent ? all_ones : gx_no_color_index); + + /* Check for constant source. */ + if ( scolors != 0 && scolors[0] == scolors[1] ) + { /* Constant source */ + const_source = scolors[0]; + if ( const_source == 0 ) + rop = (gs_rop3_t)rop3_know_S_0(rop); + else if ( const_source == all_ones ) + rop = (gs_rop3_t)rop3_know_S_1(rop); + } + else if ( !rop3_uses_S(rop) ) + const_source = 0; /* arbitrary */ + + /* Check for constant texture. */ + if ( tcolors != 0 && tcolors[0] == tcolors[1] ) + { /* Constant texture */ + const_texture = tcolors[0]; + if ( const_texture == 0 ) + rop = (gs_rop3_t)rop3_know_T_0(rop); + else if ( const_texture == all_ones ) + rop = (gs_rop3_t)rop3_know_T_1(rop); + } + else if ( !rop3_uses_T(rop) ) + const_texture = 0; /* arbitrary */ + + /* Adjust coordinates to be in bounds. */ + if ( const_source == gx_no_color_index ) + { fit_copy(dev, sdata, sourcex, sraster, id, + x, y, width, height); + } + else + { fit_fill(dev, x, y, width, height); + } + + /* Set up transfer parameters. */ + line_count = height; + drow = scan_line_base(mdev, y) + x * bpp; + + /* + * There are 18 cases depending on whether each of the source and + * texture is constant, 1-bit, or multi-bit, and on whether the + * depth is 8 or 24 bits. We divide first according to constant + * vs. non-constant, and then according to 1- vs. multi-bit, and + * finally according to pixel depth. This minimizes source code, + * but not necessarily time, since we do some of the divisions + * within 1 or 2 levels of loop. + */ + +#define dbit(base, i) ((base)[(i) >> 3] & (0x80 >> ((i) & 7))) +/* 8-bit */ +#define cbit8(base, i, colors)\ + (dbit(base, i) ? (byte)colors[1] : (byte)colors[0]) +#define rop_body_8()\ + if ( s_pixel == strans || /* So = 0, s_tr = 1 */\ + t_pixel == ttrans /* Po = 0, p_tr = 1 */\ + )\ + continue;\ + *dptr = (*rop_proc_tab[rop])(*dptr, s_pixel, t_pixel) +/* 24-bit */ +#define get24(ptr)\ + (((gx_color_index)(ptr)[0] << 16) | ((gx_color_index)(ptr)[1] << 8) | (ptr)[2]) +#define put24(ptr, pixel)\ + (ptr)[0] = (byte)((pixel) >> 16),\ + (ptr)[1] = (byte)((uint)(pixel) >> 8),\ + (ptr)[2] = (byte)(pixel) +#define cbit24(base, i, colors)\ + (dbit(base, i) ? colors[1] : colors[0]) +#define rop_body_24()\ + if ( s_pixel == strans || /* So = 0, s_tr = 1 */\ + t_pixel == ttrans /* Po = 0, p_tr = 1 */\ + )\ + continue;\ + { gx_color_index d_pixel = get24(dptr);\ + d_pixel = (*rop_proc_tab[rop])(d_pixel, s_pixel, t_pixel);\ + put24(dptr, d_pixel);\ + } + + if ( const_texture != gx_no_color_index ) /**** Constant texture ****/ + { + if ( const_source != gx_no_color_index ) /**** Constant source & texture ****/ + { + for ( ; line_count-- > 0; drow += draster ) + { byte *dptr = drow; + int left = width; + if ( bpp == 1 ) /**** 8-bit destination ****/ +#define s_pixel (byte)const_source +#define t_pixel (byte)const_texture + for ( ; left > 0; ++dptr, --left ) + { rop_body_8(); + } +#undef s_pixel +#undef t_pixel + else /**** 24-bit destination ****/ +#define s_pixel const_source +#define t_pixel const_texture + for ( ; left > 0; dptr += 3, --left ) + { rop_body_24(); + } +#undef s_pixel +#undef t_pixel + } + } + else /**** Data source, const texture ****/ + { const byte *srow = sdata; + for ( ; line_count-- > 0; drow += draster, srow += sraster ) + { byte *dptr = drow; + int left = width; + if ( scolors ) /**** 1-bit source ****/ + { int sx = sourcex; + if ( bpp == 1 ) /**** 8-bit destination ****/ +#define t_pixel (byte)const_texture + for ( ; left > 0; ++dptr, ++sx, --left ) + { byte s_pixel = cbit8(srow, sx, scolors); + rop_body_8(); + } +#undef t_pixel + else /**** 24-bit destination ****/ +#define t_pixel const_texture + for ( ; left > 0; dptr += 3, ++sx, --left ) + { bits32 s_pixel = cbit24(srow, sx, scolors); + rop_body_24(); + } +#undef t_pixel + } + else if ( bpp == 1) /**** 8-bit source & dest ****/ + { const byte *sptr = srow + sourcex; +#define t_pixel (byte)const_texture + for ( ; left > 0; ++dptr, ++sptr, --left ) + { byte s_pixel = *sptr; + rop_body_8(); + } +#undef t_pixel + } + else /**** 24-bit source & dest ****/ + { const byte *sptr = srow + sourcex * 3; +#define t_pixel const_texture + for ( ; left > 0; dptr += 3, sptr += 3, --left ) + { bits32 s_pixel = get24(sptr); + rop_body_24(); + } +#undef t_pixel + } + } + } + } + else if ( const_source != gx_no_color_index ) /**** Const source, data texture ****/ + { uint traster = textures->raster; + int ty = y + phase_y; + + for ( ; line_count-- > 0; drow += draster, ++ty ) + { /* Loop over copies of the tile. */ + int dx = x, w = width, nw; + byte *dptr = drow; + const byte *trow = + textures->data + (ty % textures->size.y) * traster; + int xoff = x_offset(phase_x, ty, textures); + + for ( ; w > 0; dx += nw, w -= nw ) + { int tx = (dx + xoff) % textures->rep_width; + int left = nw = min(w, textures->size.x - tx); + const byte *tptr = trow; + + if ( tcolors ) /**** 1-bit texture ****/ + { if ( bpp == 1 ) /**** 8-bit dest ****/ +#define s_pixel (byte)const_source + for ( ; left > 0; ++dptr, ++tx, --left ) + { byte t_pixel = cbit8(tptr, tx, tcolors); + rop_body_8(); + } +#undef s_pixel + else /**** 24-bit dest ****/ +#define s_pixel const_source + for ( ; left > 0; dptr += 3, ++tx, --left ) + { bits32 t_pixel = cbit24(tptr, tx, tcolors); + rop_body_24(); + } +#undef s_pixel + } + else if ( bpp == 1 ) /**** 8-bit T & D ****/ + { tptr += tx; +#define s_pixel (byte)const_source + for ( ; left > 0; ++dptr, ++tptr, --left ) + { byte t_pixel = *tptr; + rop_body_8(); + } +#undef s_pixel + } + else /**** 24-bit T & D ****/ + { tptr += tx * 3; +#define s_pixel const_source + for ( ; left > 0; dptr += 3, tptr += 3, --left ) + { bits32 t_pixel = get24(tptr); + rop_body_24(); + } +#undef s_pixel + } + } + } + } + else /**** Data source & texture ****/ + { + uint traster = textures->raster; + int ty = y + phase_y; + const byte *srow = sdata; + + /* Loop over scan lines. */ + for ( ; line_count-- > 0; drow += draster, srow += sraster, ++ty ) + { /* Loop over copies of the tile. */ + int sx = sourcex; + int dx = x; + int w = width; + int nw; + byte *dptr = drow; + const byte *trow = + textures->data + (ty % textures->size.y) * traster; + int xoff = x_offset(phase_x, ty, textures); + + for ( ; w > 0; dx += nw, w -= nw ) + { /* Loop over individual pixels. */ + int tx = (dx + xoff) % textures->rep_width; + int left = nw = min(w, textures->size.x - tx); + const byte *tptr = trow; + + /* + * For maximum speed, we should split this loop + * into 7 cases depending on source & texture + * depth: (1,1), (1,8), (1,24), (8,1), (8,8), + * (24,1), (24,24). But since we expect these + * cases to be relatively uncommon, we just + * divide on the destination depth. + */ + if ( bpp == 1 ) /**** 8-bit destination ****/ + { const byte *sptr = srow + sx; + tptr += tx; + for ( ; left > 0; ++dptr, ++sptr, ++tptr, ++sx, ++tx, --left ) + { byte s_pixel = + (scolors ? cbit8(srow, sx, scolors) : *sptr); + byte t_pixel = + (tcolors ? cbit8(tptr, tx, tcolors) : *tptr); + rop_body_8(); + } + } + else /**** 24-bit destination ****/ + { const byte *sptr = srow + sx * 3; + tptr += tx * 3; + for ( ; left > 0; dptr += 3, sptr += 3, tptr += 3, ++sx, ++tx, --left ) + { bits32 s_pixel = + (scolors ? cbit24(srow, sx, scolors) : + get24(sptr)); + bits32 t_pixel = + (tcolors ? cbit24(tptr, tx, tcolors) : + get24(tptr)); + rop_body_24(); + } + } + } + } + } +#undef rop_body_8 +#undef rop_body_24 +#undef dbit +#undef cbit8 +#undef cbit24 + return 0; +} + +/* ---------------- Default copy_rop implementations ---------------- */ + +#undef mdev + +int +gx_real_default_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_tile_bitmap *texture, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ const gx_strip_bitmap *textures; + gx_strip_bitmap tiles; + + if ( texture == 0 ) + textures = 0; + else + { *(gx_tile_bitmap *)&tiles = *texture; + tiles.rep_shift = tiles.shift = 0; + textures = &tiles; + } + return (*dev_proc(dev, strip_copy_rop)) + (dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, + x, y, width, height, phase_x, phase_y, lop); +} + +int +gx_real_default_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ /* + * The default implementation uses get_bits to read out the + * pixels, the memory device implementation to do the operation, + * and copy_color to write the pixels back. + */ + gs_rop3_t rop = (gs_rop3_t)(lop & lop_rop_mask); + int depth = dev->color_info.depth; + const gx_device_memory *mdproto = gdev_mem_device_for_bits(depth); + gx_device_memory mdev; + uint draster = gx_device_raster(dev, true); + bool uses_d = rop3_uses_D(rop); + byte *row; + int code; + int py; + +#ifdef DEBUG + if ( gs_debug_c('b') ) + trace_copy_rop("gx_default_strip_copy_rop", + dev, sdata, sourcex, sraster, + id, scolors, textures, tcolors, + x, y, width, height, phase_x, phase_y, lop); +#endif + if ( mdproto == 0 ) + return_error(gs_error_rangecheck); + gs_make_mem_device(&mdev, mdproto, 0, -1, dev); + mdev.width = width; + mdev.height = 1; + mdev.bitmap_memory = &gs_memory_default; + code = (*dev_proc(&mdev, open_device))((gx_device *)&mdev); + if ( code < 0 ) + return code; + row = gs_malloc(1, draster, "copy_rop buffer"); + if ( row == 0 ) + { (*dev_proc(&mdev, close_device))((gx_device *)&mdev); + return_error(gs_error_VMerror); + } + for ( py = y; py < y + height; ++py ) + { byte *data; + + if ( uses_d ) + { code = (*dev_proc(dev, get_bits))(dev, py, row, &data); + if ( code < 0 ) + break; + code = (*dev_proc(&mdev, copy_color))((gx_device *)&mdev, + data, x, draster, gx_no_bitmap_id, + 0, 0, width, 1); + if ( code < 0 ) + return code; + } + code = (*dev_proc(&mdev, strip_copy_rop))((gx_device *)&mdev, + sdata + (py - y) * sraster, sourcex, sraster, + gx_no_bitmap_id, scolors, textures, tcolors, + 0, 0, width, 1, phase_x + x, phase_y + py, + lop); + if ( code < 0 ) + break; + code = (*dev_proc(&mdev, get_bits))((gx_device *)&mdev, 0, row, &data); + if ( code < 0 ) + break; + code = (*dev_proc(dev, copy_color))(dev, + data, 0, draster, gx_no_bitmap_id, + x, py, width, 1); + if ( code < 0 ) + break; + } + gs_free(row, 1, draster, "copy_rop buffer"); + (*dev_proc(&mdev, close_device))((gx_device *)&mdev); + return code; +} + +int +gx_forward_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_tile_bitmap *texture, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ gx_device *tdev = ((gx_device_forward *)dev)->target; + dev_proc_copy_rop((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_copy_rop; + else + proc = dev_proc(tdev, copy_rop); + return (*proc)(tdev, sdata, sourcex, sraster, id, scolors, + texture, tcolors, x, y, width, height, + phase_x, phase_y, lop); +} + +int +gx_forward_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ gx_device *tdev = ((gx_device_forward *)dev)->target; + dev_proc_strip_copy_rop((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_strip_copy_rop; + else + proc = dev_proc(tdev, strip_copy_rop); + return (*proc)(tdev, sdata, sourcex, sraster, id, scolors, + textures, tcolors, x, y, width, height, + phase_x, phase_y, lop); +} + +int +gx_copy_rop_unaligned(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_tile_bitmap *texture, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ const gx_strip_bitmap *textures; + gx_strip_bitmap tiles; + + if ( texture == 0 ) + textures = 0; + else + { *(gx_tile_bitmap *)&tiles = *texture; + tiles.rep_shift = tiles.shift = 0; + textures = &tiles; + } + return gx_strip_copy_rop_unaligned + (dev, sdata, sourcex, sraster, id, scolors, textures, tcolors, + x, y, width, height, phase_x, phase_y, lop); +} + +int +gx_strip_copy_rop_unaligned(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ dev_proc_strip_copy_rop((*copy_rop)) = dev_proc(dev, strip_copy_rop); + int depth = (scolors == 0 ? dev->color_info.depth : 1); + int step = sraster & (align_bitmap_mod - 1); + + /* Adjust the origin. */ + if ( sdata != 0 ) + { uint offset = + (uint)(sdata - (const byte *)0) & (align_bitmap_mod - 1); + /* See copy_color above re the following statement. */ + if ( depth == 24 ) + offset += (offset % 3) * + (align_bitmap_mod * (3 - (align_bitmap_mod % 3))); + sdata -= offset; + sourcex += (offset << 3) / depth; + } + + /* Adjust the raster. */ + if ( !step || sdata == 0 || + (scolors != 0 && scolors[0] == scolors[1]) + ) + { /* No adjustment needed. */ + return (*copy_rop)(dev, sdata, sourcex, sraster, id, scolors, + textures, tcolors, x, y, width, height, + phase_x, phase_y, lop); + } + + /* Do the transfer one scan line at a time. */ + { const byte *p = sdata; + int d = sourcex; + int dstep = (step << 3) / depth; + int code = 0; + int i; + + for ( i = 0; i < height && code >= 0; + ++i, p += sraster - step, d += dstep + ) + code = (*copy_rop)(dev, p, d, sraster, gx_no_bitmap_id, scolors, + textures, tcolors, x, y + i, width, 1, + phase_x, phase_y, lop); + return code; + } +} + +/* ---------------- RasterOp texture device ---------------- */ + +public_st_device_rop_texture(); + +/* Device for clipping with a region. */ +private dev_proc_fill_rectangle(rop_texture_fill_rectangle); +private dev_proc_copy_mono(rop_texture_copy_mono); +private dev_proc_copy_color(rop_texture_copy_color); + +/* The device descriptor. */ +private const gx_device_rop_texture far_data gs_rop_texture_device = +{ std_device_std_body(gx_device_rop_texture, 0, "rop source", + 0, 0, 1, 1), + { gx_default_open_device, + NULL, /* get_initial_matrix */ + gx_default_sync_output, + gx_default_output_page, + gx_default_close_device, + NULL, /* map_rgb_color */ + NULL, /* map_color_rgb */ + rop_texture_fill_rectangle, + gx_default_tile_rectangle, + rop_texture_copy_mono, + rop_texture_copy_color, + gx_default_draw_line, + NULL, /* get_bits */ + NULL, /* get_params */ + NULL, /* put_params */ + NULL, /* map_cmyk_color */ + NULL, /* get_xfont_procs */ + NULL, /* get_xfont_device */ + NULL, /* map_rgb_alpha_color */ + NULL, /* get_page_device */ + gx_default_get_alpha_bits, /* (no alpha) */ + gx_no_copy_alpha, /* shouldn't be called */ + NULL, /* get_band */ + gx_no_copy_rop /* shouldn't be called */ + }, + 0, /* target */ + lop_default, /* log_op */ + NULL /* texture */ +}; +#define rtdev ((gx_device_rop_texture *)dev) + +/* Initialize a RasterOp source device. */ +void +gx_make_rop_texture_device(gx_device_rop_texture *dev, gx_device *target, + gs_logical_operation_t log_op, const gx_device_color *texture) +{ *dev = gs_rop_texture_device; + gx_device_forward_fill_in_procs((gx_device_forward *)dev); + dev->color_info = target->color_info; + dev->target = target; + dev->log_op = log_op; + dev->texture = texture; +} + +/* Fill a rectangle */ +private int +rop_texture_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ gx_rop_source_t source; + + source.sdata = NULL; + source.sourcex = 0; + source.sraster = 0; + source.id = gx_no_bitmap_id; + source.scolors[0] = source.scolors[1] = color; + return gx_device_color_fill_rectangle(rtdev->texture, + x, y, w, h, rtdev->target, + rtdev->log_op, &source); +} + +/* Copy a monochrome rectangle */ +private int +rop_texture_copy_mono(gx_device *dev, + const byte *data, int sourcex, int raster, gx_bitmap_id id, + int x, int y, int w, int h, + gx_color_index color0, gx_color_index color1) +{ gx_rop_source_t source; + gs_logical_operation_t lop = rtdev->log_op; + + source.sdata = data; + source.sourcex = sourcex; + source.sraster = raster; + source.id = id; + source.scolors[0] = color0; + source.scolors[1] = color1; + /* Adjust the logical operation per transparent colors. */ + if ( color0 == gx_no_color_index ) + lop = rop3_use_D_when_S_0(lop); + else if ( color1 == gx_no_color_index ) + lop = rop3_use_D_when_S_1(lop); + return gx_device_color_fill_rectangle(rtdev->texture, + x, y, w, h, rtdev->target, + lop, &source); +} + +/* Copy a color rectangle */ +private int +rop_texture_copy_color(gx_device *dev, + const byte *data, int sourcex, int raster, gx_bitmap_id id, + int x, int y, int w, int h) +{ gx_rop_source_t source; + + source.sdata = data; + source.sourcex = sourcex; + source.sraster = raster; + source.id = id; + source.scolors[0] = source.scolors[1] = gx_no_color_index; + return gx_device_color_fill_rectangle(rtdev->texture, + x, y, w, h, rtdev->target, + rtdev->log_op, &source); +} + +/* ---------------- Internal routines ---------------- */ + +/* Compute the effective RasterOp for the 1-bit case, */ +/* taking transparency into account. */ +private gs_rop3_t +gs_transparent_rop(gs_rop3_t rop, bool source_transparent, + bool pattern_transparent) +{ /* + * The algorithm for computing an effective RasterOp is presented, + * albeit obfuscated, in the H-P PCL5 technical documentation. + * One applies the original RasterOp to compute an intermediate + * result R, and then computes the final result as + * (R & M) | (D & ~M) where M depends on transparencies as follows: + * s_tr p_tr M + * 0 0 1 + * 0 1 ~So | Po (? Po ?) + * 1 0 So + * 1 1 So & Po + * or equivalently + * So Po M + * 0 0 ~s_tr (? ~s_tr & ~p_tr ?) + * 0 1 ~s_tr + * 1 0 ~p_tr + * 1 1 1 + * The s_tr = 0, p_tr = 1 case seems wrong, but it's clearly + * specified that way in the "PCL 5 Color Technical Reference + * Manual." So and Po are "source opaque" and "pattern opaque"; + * in the uninverted 1-bit case with black = 0, these are + * equivalent to ~S and ~P. + */ +#define So rop3_not(rop3_S) +#define Po rop3_not(rop3_T) + gs_rop3_t mask = + (gs_rop3_t)(source_transparent ? + (pattern_transparent ? So & Po : So) : + (pattern_transparent ? ~So | Po : rop3_1)); + return (gs_rop3_t)((rop & mask) | (rop3_D & ~mask)); +} diff --git a/pstoraster/gdevmrop.h b/pstoraster/gdevmrop.h new file mode 100644 index 0000000000..65699e51c7 --- /dev/null +++ b/pstoraster/gdevmrop.h @@ -0,0 +1,65 @@ +/* Copyright (C) 1995 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevmrop.h */ +/* Interfaces to RasterOp implementation */ +/* Requires gxdevmem.h, gsropt.h */ + +/* Define the table of RasterOp implementation procedures. */ +extern const far_data rop_proc rop_proc_tab[256]; + +/* + * PostScript colors normally act as the texture for RasterOp, with a null + * (all zeros) source. For images with CombineWithColor = true, we need + * a way to use the image data as the source. We implement this with a + * device that applies RasterOp with a specified texture to drawing + * operations, treating the drawing color as source rather than texture. + * The texture is a gx_device_color; it may be any type of PostScript color, + * even a Pattern. + */ +#ifndef gx_device_color_DEFINED +# define gx_device_color_DEFINED +typedef struct gx_device_color_s gx_device_color; +#endif + +#ifndef gx_device_rop_texture_DEFINED +# define gx_device_rop_texture_DEFINED +typedef struct gx_device_rop_texture_s gx_device_rop_texture; +#endif + +struct gx_device_rop_texture_s { + gx_device_forward_common; + gs_logical_operation_t log_op; + const gx_device_color *texture; +}; +extern_st(st_device_rop_texture); +#define public_st_device_rop_texture()\ + gs_public_st_suffix_add1(st_device_rop_texture, gx_device_rop_texture,\ + "gx_device_rop_texture", device_rop_texture_enum_ptrs, device_rop_texture_reloc_ptrs,\ + st_device_forward, texture) + +/* Initialize a RasterOp source device. */ +void gx_make_rop_texture_device(P4(gx_device_rop_texture *rsdev, + gx_device *target, + gs_logical_operation_t lop, + const gx_device_color *texture)); diff --git a/pstoraster/gdevnfwd.c b/pstoraster/gdevnfwd.c new file mode 100644 index 0000000000..c65b6c4013 --- /dev/null +++ b/pstoraster/gdevnfwd.c @@ -0,0 +1,561 @@ +/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevnfwd.c */ +/* Null and forwarding device implementation */ +#include "gx.h" +#include "gxdevice.h" + +/* ---------------- Forwarding procedures ---------------- */ + +#define fdev ((gx_device_forward *)dev) + +/* Fill in NULL procedures in a forwarding device procedure record. */ +/* We don't fill in: open_device, close_device, or the lowest-level */ +/* drawing operations. */ +void +gx_device_forward_fill_in_procs(register gx_device_forward *dev) +{ gx_device_set_procs((gx_device *)dev); + /* NOT open_device */ + fill_dev_proc(dev, get_initial_matrix, gx_forward_get_initial_matrix); + fill_dev_proc(dev, sync_output, gx_forward_sync_output); + fill_dev_proc(dev, output_page, gx_forward_output_page); + /* NOT close_device */ + fill_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color); + fill_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb); + /* NOT fill_rectangle */ + /* NOT tile_rectangle */ + /* NOT copy_mono */ + /* NOT copy_color */ + /* NOT draw_line (OBSOLETE) */ + fill_dev_proc(dev, get_bits, gx_forward_get_bits); + fill_dev_proc(dev, get_params, gx_forward_get_params); + fill_dev_proc(dev, put_params, gx_forward_put_params); + fill_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color); + fill_dev_proc(dev, get_xfont_procs, gx_forward_get_xfont_procs); + fill_dev_proc(dev, get_xfont_device, gx_forward_get_xfont_device); + fill_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color); + fill_dev_proc(dev, get_page_device, gx_forward_get_page_device); + fill_dev_proc(dev, get_alpha_bits, gx_forward_get_alpha_bits); + /* NOT copy_alpha */ + fill_dev_proc(dev, get_band, gx_forward_get_band); + fill_dev_proc(dev, copy_rop, gx_forward_copy_rop_proc); + fill_dev_proc(dev, fill_path, gx_forward_fill_path); + fill_dev_proc(dev, stroke_path, gx_forward_stroke_path); + fill_dev_proc(dev, fill_mask, gx_forward_fill_mask); + fill_dev_proc(dev, fill_trapezoid, gx_forward_fill_trapezoid); + fill_dev_proc(dev, fill_parallelogram, gx_forward_fill_parallelogram); + fill_dev_proc(dev, fill_triangle, gx_forward_fill_triangle); + fill_dev_proc(dev, draw_thin_line, gx_forward_draw_thin_line); + fill_dev_proc(dev, begin_image, gx_forward_begin_image); + fill_dev_proc(dev, image_data, gx_forward_image_data); + fill_dev_proc(dev, end_image, gx_forward_end_image); + /* NOT strip_tile_rectangle */ + fill_dev_proc(dev, strip_copy_rop, gx_forward_strip_copy_rop_proc); + gx_device_fill_in_procs((gx_device *)dev); +} + +/* Forward the color mapping procedures from a device to its target. */ +void +gx_device_forward_color_procs(gx_device_forward *dev) +{ set_dev_proc(dev, map_rgb_color, gx_forward_map_rgb_color); + set_dev_proc(dev, map_color_rgb, gx_forward_map_color_rgb); + set_dev_proc(dev, map_cmyk_color, gx_forward_map_cmyk_color); + set_dev_proc(dev, map_rgb_alpha_color, gx_forward_map_rgb_alpha_color); +} + +void +gx_forward_get_initial_matrix(gx_device *dev, gs_matrix *pmat) +{ gx_device *tdev = fdev->target; + if ( tdev == 0 ) + gx_default_get_initial_matrix(dev, pmat); + else + (*dev_proc(tdev, get_initial_matrix))(tdev, pmat); +} + +int +gx_forward_sync_output(gx_device *dev) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_sync_output(dev) : + (*dev_proc(tdev, sync_output))(tdev)); +} + +int +gx_forward_output_page(gx_device *dev, int num_copies, int flush) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_output_page(dev, num_copies, flush) : + (*dev_proc(tdev, output_page))(tdev, num_copies, flush)); +} + +gx_color_index +gx_forward_map_rgb_color(gx_device *dev, gx_color_value r, gx_color_value g, + gx_color_value b) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_map_rgb_color(dev, r, g, b) : + (*dev_proc(tdev, map_rgb_color))(tdev, r, g, b)); +} + +int +gx_forward_map_color_rgb(gx_device *dev, gx_color_index color, + gx_color_value prgb[3]) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_map_color_rgb(dev, color, prgb) : + (*dev_proc(tdev, map_color_rgb))(tdev, color, prgb)); +} + +int +gx_forward_tile_rectangle(gx_device *dev, const gx_tile_bitmap *tile, + int x, int y, int w, int h, gx_color_index color0, gx_color_index color1, + int px, int py) +{ gx_device *tdev = fdev->target; + dev_proc_tile_rectangle((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_tile_rectangle; + else + proc = dev_proc(tdev, tile_rectangle); + return (*proc)(tdev, tile, x, y, w, h, color0, color1, px, py); +} + +int +gx_forward_get_bits(gx_device *dev, int y, byte *data, byte **actual_data) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_get_bits(dev, y, data, actual_data) : + (*dev_proc(tdev, get_bits))(tdev, y, data, actual_data)); +} + +int +gx_forward_get_params(gx_device *dev, gs_param_list *plist) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_get_params(dev, plist) : + (*dev_proc(tdev, get_params))(tdev, plist)); +} + +int +gx_forward_put_params(gx_device *dev, gs_param_list *plist) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_put_params(dev, plist) : + (*dev_proc(tdev, put_params))(tdev, plist)); +} + +gx_color_index +gx_forward_map_cmyk_color(gx_device *dev, gx_color_value c, gx_color_value m, + gx_color_value y, gx_color_value k) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_map_cmyk_color(dev, c, m, y, k) : + (*dev_proc(tdev, map_cmyk_color))(tdev, c, m, y, k)); +} + +gx_xfont_procs * +gx_forward_get_xfont_procs(gx_device *dev) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_get_xfont_procs(dev) : + (*dev_proc(tdev, get_xfont_procs))(tdev)); +} + +gx_device * +gx_forward_get_xfont_device(gx_device *dev) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_get_xfont_device(dev) : + (*dev_proc(tdev, get_xfont_device))(tdev)); +} + +gx_color_index +gx_forward_map_rgb_alpha_color(gx_device *dev, gx_color_value r, + gx_color_value g, gx_color_value b, gx_color_value alpha) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? + gx_default_map_rgb_alpha_color(dev, r, g, b, alpha) : + (*dev_proc(tdev, map_rgb_alpha_color))(tdev, r, g, b, alpha)); +} + +gx_device * +gx_forward_get_page_device(gx_device *dev) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? gx_default_get_page_device(dev) : + (*dev_proc(tdev, get_page_device))(tdev)); +} + +int +gx_forward_get_alpha_bits(gx_device *dev, graphics_object_type type) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? + gx_default_get_alpha_bits(dev, type) : + (*dev_proc(tdev, get_alpha_bits))(tdev, type)); +} + +int +gx_forward_get_band(gx_device *dev, int y, int *band_start) +{ gx_device *tdev = fdev->target; + return (tdev == 0 ? + gx_default_get_band(dev, y, band_start) : + (*dev_proc(tdev, get_band))(tdev, y, band_start)); +} + +int +gx_forward_fill_path(gx_device *dev, const gs_imager_state *pis, + gx_path *ppath, const gx_fill_params *params, + const gx_drawing_color *pdcolor, const gx_clip_path *pcpath) +{ gx_device *tdev = fdev->target; + dev_proc_fill_path((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_fill_path; + else + proc = dev_proc(tdev, fill_path); + return (*proc)(tdev, pis, ppath, params, pdcolor, pcpath); +} + +int +gx_forward_stroke_path(gx_device *dev, const gs_imager_state *pis, + gx_path *ppath, const gx_stroke_params *params, + const gx_drawing_color *pdcolor, const gx_clip_path *pcpath) +{ gx_device *tdev = fdev->target; + dev_proc_stroke_path((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_stroke_path; + else + proc = dev_proc(tdev, stroke_path); + return (*proc)(tdev, pis, ppath, params, pdcolor, pcpath); +} + +int +gx_forward_fill_mask(gx_device *dev, + const byte *data, int dx, int raster, gx_bitmap_id id, + int x, int y, int w, int h, + const gx_drawing_color *pdcolor, int depth, + gs_logical_operation_t lop, const gx_clip_path *pcpath) +{ gx_device *tdev = fdev->target; + dev_proc_fill_mask((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_fill_mask; + else + proc = dev_proc(tdev, fill_mask); + return (*proc)(dev, data, dx, raster, id, x, y, w, h, pdcolor, depth, + lop, pcpath); +} + +int +gx_forward_fill_trapezoid(gx_device *dev, + const gs_fixed_edge *left, const gs_fixed_edge *right, + fixed ybot, fixed ytop, bool swap_axes, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ gx_device *tdev = fdev->target; + dev_proc_fill_trapezoid((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_fill_trapezoid; + else + proc = dev_proc(tdev, fill_trapezoid); + return (*proc)(tdev, left, right, ybot, ytop, swap_axes, pdcolor, lop); +} + +int +gx_forward_fill_parallelogram(gx_device *dev, + fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ gx_device *tdev = fdev->target; + dev_proc_fill_parallelogram((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_fill_parallelogram; + else + proc = dev_proc(tdev, fill_parallelogram); + return (*proc)(tdev, px, py, ax, ay, bx, by, pdcolor, lop); +} + +int +gx_forward_fill_triangle(gx_device *dev, + fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ gx_device *tdev = fdev->target; + dev_proc_fill_triangle((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_fill_triangle; + else + proc = dev_proc(tdev, fill_triangle); + return (*proc)(tdev, px, py, ax, ay, bx, by, pdcolor, lop); +} + +int +gx_forward_draw_thin_line(gx_device *dev, + fixed fx0, fixed fy0, fixed fx1, fixed fy1, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ gx_device *tdev = fdev->target; + dev_proc_draw_thin_line((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_draw_thin_line; + else + proc = dev_proc(tdev, draw_thin_line); + return (*proc)(tdev, fx0, fy0, fx1, fy1, pdcolor, lop); +} + +int +gx_forward_begin_image(gx_device *dev, + const gs_imager_state *pis, const gs_image_t *pim, + gs_image_format_t format, gs_image_shape_t shape, + const gx_drawing_color *pdcolor, const gx_clip_path *pcpath, + gs_memory_t *memory, void **pinfo) +{ gx_device *tdev = fdev->target; + dev_proc_begin_image((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_begin_image; + else + proc = dev_proc(tdev, begin_image); + return (*proc)(tdev, pis, pim, format, shape, pdcolor, pcpath, + memory, pinfo); +} + +int +gx_forward_image_data(gx_device *dev, + void *info, const byte **planes, uint raster, + int x, int y, int width, int height) +{ gx_device *tdev = fdev->target; + dev_proc_image_data((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_image_data; + else + proc = dev_proc(tdev, image_data); + return (*proc)(tdev, info, planes, raster, x, y, width, height); +} + +int +gx_forward_end_image(gx_device *dev, + void *info, bool draw_last) +{ gx_device *tdev = fdev->target; + dev_proc_end_image((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_end_image; + else + proc = dev_proc(tdev, end_image); + return (*proc)(tdev, info, draw_last); +} + +int +gx_forward_strip_tile_rectangle(gx_device *dev, const gx_strip_bitmap *tiles, + int x, int y, int w, int h, gx_color_index color0, gx_color_index color1, + int px, int py) +{ gx_device *tdev = fdev->target; + dev_proc_strip_tile_rectangle((*proc)); + + if ( tdev == 0 ) + tdev = dev, proc = gx_default_strip_tile_rectangle; + else + proc = dev_proc(tdev, strip_tile_rectangle); + return (*proc)(tdev, tiles, x, y, w, h, color0, color1, px, py); +} + +/* ---------------- The null device(s) ---------------- */ + +private dev_proc_fill_rectangle(null_fill_rectangle); +private dev_proc_copy_mono(null_copy_mono); +private dev_proc_copy_color(null_copy_color); +private dev_proc_put_params(null_put_params); +private dev_proc_copy_alpha(null_copy_alpha); +private dev_proc_copy_rop(null_copy_rop); +private dev_proc_fill_path(null_fill_path); +private dev_proc_stroke_path(null_stroke_path); +private dev_proc_fill_trapezoid(null_fill_trapezoid); +private dev_proc_fill_parallelogram(null_fill_parallelogram); +private dev_proc_fill_triangle(null_fill_triangle); +private dev_proc_draw_thin_line(null_draw_thin_line); +private dev_proc_begin_image(null_begin_image); +private dev_proc_image_data(null_image_data); +private dev_proc_end_image(null_end_image); +private dev_proc_strip_copy_rop(null_strip_copy_rop); + +#define null_procs(get_page_device) {\ + gx_default_open_device,\ + gx_forward_get_initial_matrix,\ + gx_default_sync_output,\ + gx_default_output_page,\ + gx_default_close_device,\ + gx_forward_map_rgb_color,\ + gx_forward_map_color_rgb,\ + null_fill_rectangle,\ + gx_default_tile_rectangle,\ + null_copy_mono,\ + null_copy_color,\ + gx_default_draw_line,\ + gx_default_get_bits,\ + gx_forward_get_params,\ + null_put_params,\ + gx_forward_map_cmyk_color,\ + gx_forward_get_xfont_procs,\ + gx_forward_get_xfont_device,\ + gx_forward_map_rgb_alpha_color,\ + get_page_device, /* differs */\ + gx_forward_get_alpha_bits,\ + null_copy_alpha,\ + gx_forward_get_band,\ + null_copy_rop,\ + null_fill_path,\ + null_stroke_path,\ + gx_default_fill_mask,\ + null_fill_trapezoid,\ + null_fill_parallelogram,\ + null_fill_triangle,\ + null_draw_thin_line,\ + null_begin_image,\ + null_image_data,\ + null_end_image,\ + gx_default_strip_tile_rectangle,\ + null_strip_copy_rop,\ +} + +gx_device_null far_data gs_null_device = { + std_device_std_body_open(gx_device_null, 0, "null", + 0, 0, 72, 72), + null_procs(gx_default_get_page_device /* not a page device */), + 0 /* target */ +}; + +gx_device_null far_data gs_nullpage_device = { + std_device_std_body_open(gx_device_null, 0, "nullpage", + 0, 0, 72, 72), + null_procs(gx_page_device_get_page_device /* a page device */), + 0 /* target */ +}; + +private int +null_fill_rectangle(gx_device *dev, int x, int y, int w, int h, + gx_color_index color) +{ return 0; +} +private int +null_copy_mono(gx_device *dev, const byte *data, + int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h, + gx_color_index zero, gx_color_index one) +{ return 0; +} +private int +null_copy_color(gx_device *dev, const byte *data, + int data_x, int raster, gx_bitmap_id id, + int x, int y, int width, int height) +{ return 0; +} +private int +null_put_params(gx_device *dev, gs_param_list *plist) +{ /* We must defeat attempts to reset the size; */ + /* otherwise this is equivalent to gx_forward_put_params. */ + gx_device *tdev = fdev->target; + int code; + + if ( tdev != 0 ) + return (*dev_proc(tdev, put_params))(tdev, plist); + code = gx_default_put_params(dev, plist); + if ( code < 0 ) + return code; + dev->width = dev->height = 0; + return code; +} +private int +null_copy_alpha(gx_device *dev, const byte *data, int data_x, + int raster, gx_bitmap_id id, int x, int y, int width, int height, + gx_color_index color, int depth) +{ return 0; +} +private int +null_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_tile_bitmap *texture, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ return 0; +} +private int +null_fill_path(gx_device *dev, const gs_imager_state *pis, + gx_path *ppath, const gx_fill_params *params, + const gx_drawing_color *pdcolor, const gx_clip_path *pcpath) +{ return 0; +} +private int +null_stroke_path(gx_device *dev, const gs_imager_state *pis, + gx_path *ppath, const gx_stroke_params *params, + const gx_drawing_color *pdcolor, const gx_clip_path *pcpath) +{ return 0; +} +private int +null_fill_trapezoid(gx_device *dev, + const gs_fixed_edge *left, const gs_fixed_edge *right, + fixed ybot, fixed ytop, bool swap_axes, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ return 0; +} +private int +null_fill_parallelogram(gx_device *dev, + fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ return 0; +} +private int +null_fill_triangle(gx_device *dev, + fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ return 0; +} +private int +null_draw_thin_line(gx_device *dev, + fixed fx0, fixed fy0, fixed fx1, fixed fy1, + const gx_drawing_color *pdcolor, gs_logical_operation_t lop) +{ return 0; +} +private int +null_begin_image(gx_device *dev, + const gs_imager_state *pis, const gs_image_t *pim, + gs_image_format_t format, gs_image_shape_t shape, + const gx_drawing_color *pdcolor, const gx_clip_path *pcpath, + gs_memory_t *memory, void **pinfo) +{ *pinfo = 0; + return 0; +} +private int +null_image_data(gx_device *dev, + void *info, const byte **planes, uint raster, + int x, int y, int width, int height) +{ return 0; +} +private int +null_end_image(gx_device *dev, + void *info, bool draw_last) +{ return 0; +} +private int +null_strip_copy_rop(gx_device *dev, + const byte *sdata, int sourcex, uint sraster, gx_bitmap_id id, + const gx_color_index *scolors, + const gx_strip_bitmap *textures, const gx_color_index *tcolors, + int x, int y, int width, int height, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ return 0; +} + +#undef fdev diff --git a/pstoraster/gdevpipe.c b/pstoraster/gdevpipe.c new file mode 100644 index 0000000000..ef6e7fa848 --- /dev/null +++ b/pstoraster/gdevpipe.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevpipe.c */ +/* %pipe% IODevice */ +#include "errno_.h" +#include "stdio_.h" +#include "string_.h" +#include "gserror.h" +#include "gstypes.h" +#include "gsmemory.h" /* for gxiodev.h */ +#include "stream.h" +#include "gxiodev.h" + +/* popen isn't POSIX-standard, so we declare it here. */ +/* Because of inconsistent (and sometimes incorrect) header files, */ +/* we must omit the argument list. */ +extern FILE *popen( /* P2(const char *, const char *) */ ); +extern int pclose(P1(FILE *)); + +/* The pipe IODevice */ +private iodev_proc_fopen(pipe_fopen); +private iodev_proc_fclose(pipe_fclose); +gx_io_device gs_iodev_pipe = { + "%pipe%", "FileSystem", + { iodev_no_init, iodev_no_open_device, + NULL /*iodev_os_open_file*/, pipe_fopen, pipe_fclose, + iodev_no_delete_file, iodev_no_rename_file, iodev_no_file_status, + iodev_no_enumerate_files, NULL, NULL, + iodev_no_get_params, iodev_no_put_params + } +}; + +/* The file device procedures */ + +private int +pipe_fopen(gx_io_device *iodev, const char *fname, const char *access, + FILE **pfile, char *rfname, uint rnamelen) +{ /* The OSF/1 1.3 library doesn't include const in the */ + /* prototype for popen.... */ + errno = 0; + *pfile = popen((char *)fname, (char *)access); + if ( *pfile == NULL ) + return_error(gs_fopen_errno_to_code(errno)); + if ( rfname != NULL ) + strcpy(rfname, fname); + return 0; +} + +private int +pipe_fclose(gx_io_device *iodev, FILE *file) +{ pclose(file); + return 0; +} diff --git a/pstoraster/gdevprn.c b/pstoraster/gdevprn.c new file mode 100644 index 0000000000..98229dbc69 --- /dev/null +++ b/pstoraster/gdevprn.c @@ -0,0 +1,757 @@ +/* + Copyright 1993-1999 by Easy Software Products. + Copyright (C) 1990, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevprn.c */ +/* Generic printer driver support */ +#include "ctype_.h" +#include "gdevprn.h" +#include "gp.h" +#include "gsparam.h" +#include "gxclio.h" +#include + +/* ---------------- Standard device procedures ---------------- */ + +/* Macros for casting the pdev argument */ +#define ppdev ((gx_device_printer *)pdev) +#define pmemdev ((gx_device_memory *)pdev) +#define pcldev (&((gx_device_clist *)pdev)->common) + +/* Define the standard printer procedure vector. */ +gx_device_procs prn_std_procs = + prn_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close); + +/* ------ Open/close ------ */ + +/* Forward references */ +private int gdev_prn_alloc(P1(gx_device *)); +private int gdev_prn_free(P1(gx_device *)); + +/* Open a generic printer device. */ +/* Specific devices may wish to extend this. */ +int +gdev_prn_open(gx_device *pdev) +{ int code; + ppdev->file = NULL; + code = gdev_prn_alloc(pdev); + if ( code < 0 ) + return code; + if ( ppdev->OpenOutputFile ) + code = gdev_prn_open_printer(pdev, 1); + return code; +} + +/* Allocate buffer space and initialize the device. */ +/* We break this out as a separate procedure so that resetting */ +/* the page dimensions doesn't have to close and reopen the device. */ +private int +gdev_prn_alloc(gx_device *pdev) +{ ulong mem_space; + byte *base = 0; + void *left = 0; + int cache_size; /* Size of tile cache in bytes */ + char *cache_env, /* Cache size environment variable */ + cache_units[255]; /* Cache size units */ + + + memset(ppdev->skip, 0, sizeof(ppdev->skip)); + ppdev->orig_procs = pdev->std_procs; + ppdev->ccfile = ppdev->cbfile = NULL; + + /* + * MRS - reset max_bitmap to the value of RIP_MAX_CACHE as necessary... + */ + + if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL) + { + switch (sscanf(cache_env, "%d%s", &cache_size, cache_units)) + { + case 0 : + cache_size = 32 * 1024 * 1024; + break; + case 1 : + cache_size *= 4 * 256 * 256; + break; + case 2 : + if (tolower(cache_units[0]) == 'g') /* Gigabytes */ + cache_size *= 1024 * 1024 * 1024; + else if (tolower(cache_units[0]) == 'm') /* Megabytes */ + cache_size *= 1024 * 1024; + else if (tolower(cache_units[0]) == 'k') /* Kilobytes */ + cache_size *= 1024; + else if (tolower(cache_units[0]) == 't') /* Tiles */ + cache_size *= 4 * 256 * 256; + break; + } + } + else + cache_size = 32 * 1024 * 1024; + + ppdev->max_bitmap = cache_size; + ppdev->use_buffer_space = cache_size / 8; + + mem_space = gdev_mem_bitmap_size(pmemdev); + + if ( mem_space >= ppdev->max_bitmap || + mem_space != (uint)mem_space || /* too big to allocate */ + (base = (byte *)gs_malloc((uint)mem_space, 1, "printer buffer")) == 0 || /* can't allocate */ + (PRN_MIN_MEMORY_LEFT != 0 && + (left = gs_malloc(PRN_MIN_MEMORY_LEFT, 1, "printer memory left")) == 0) /* not enough left */ + ) + { /* Buffer the image in a command list. */ + uint space; + int code, bcode = 0, ccode = 0; + + /* Release the buffer if we allocated it. */ + gs_free(base, (uint)mem_space, 1, "printer buffer(open)"); + for ( space = ppdev->use_buffer_space; ; ) + { base = (byte *)gs_malloc(space, 1, + "command list buffer"); + if ( base != 0 ) break; + if ( (space >>= 1) < PRN_MIN_BUFFER_SPACE ) + return_error(gs_error_VMerror); /* no hope */ + } +open_c: pcldev->data = base; + pcldev->data_size = space; + pcldev->target = pdev; + pcldev->make_buffer_device = + ppdev->printer_procs.make_buffer_device; + ppdev->buf = base; + ppdev->buffer_space = space; + + /* Try opening the command list, to see if we allocated */ + /* enough buffer space. */ + code = (*gs_clist_device_procs.open_device)((gx_device *)pcldev); + if ( code < 0 ) + { /* If there wasn't enough room, and we haven't */ + /* already shrunk the buffer, try enlarging it. */ + if ( code == gs_error_limitcheck && + space >= ppdev->use_buffer_space + ) + { gs_free(base, space, 1, + "command list buffer(retry open)"); + space <<= 1; + base = (byte *)gs_malloc(space, 1, + "command list buffer(retry open)"); + ppdev->buf = base; + if ( base != 0 ) + goto open_c; + } + /* Fall through with code < 0 */ + } + if ( code < 0 || + (ccode = clist_open_scratch(ppdev->ccfname, &ppdev->ccfile, &gs_memory_default, true)) < 0 || + (bcode = clist_open_scratch(ppdev->cbfname, &ppdev->cbfile, &gs_memory_default, false)) < 0 + ) + { /* Clean up before exiting */ + eprintf3("Problem opening clist: code=%d, bcode=%d, ccode=%d\n", + code, bcode, ccode); + gdev_prn_free(pdev); + return (code < 0 ? code : ccode < 0 ? ccode : bcode); + } + pcldev->cfile = ppdev->ccfile; + pcldev->bfile = ppdev->cbfile; + pcldev->bfile_end_pos = 0; + ppdev->std_procs = gs_clist_device_procs; + } + else + { /* Render entirely in memory. */ + int code; + /* Release the leftover memory. */ + gs_free(left, PRN_MIN_MEMORY_LEFT, 1, + "printer memory left"); + ppdev->buffer_space = 0; + code = (*ppdev->printer_procs.make_buffer_device) + (pmemdev, pdev, pdev->memory, false); + if ( code < 0 ) + { gs_free(base, space, 1, "command list buffer"); + return code; + } + pmemdev->base = base; + } + + /* Synthesize the procedure vector. */ + /* Rendering operations come from the memory or clist device, */ + /* non-rendering come from the printer device. */ +#define copy_proc(p) set_dev_proc(ppdev, p, ppdev->orig_procs.p) + copy_proc(get_initial_matrix); + copy_proc(output_page); + copy_proc(close_device); + copy_proc(map_rgb_color); + copy_proc(map_color_rgb); + copy_proc(get_params); + copy_proc(put_params); + copy_proc(map_cmyk_color); + copy_proc(get_xfont_procs); + copy_proc(get_xfont_device); + copy_proc(map_rgb_alpha_color); + /* All printers are page devices, even if they didn't use the */ + /* standard macros for generating their procedure vectors. */ + set_dev_proc(ppdev, get_page_device, gx_page_device_get_page_device); + copy_proc(get_alpha_bits); +#undef copy_proc + return (*dev_proc(pdev, open_device))(pdev); +} + +/* Generic closing for the printer device. */ +/* Specific devices may wish to extend this. */ +int +gdev_prn_close(gx_device *pdev) +{ gdev_prn_free(pdev); + if ( ppdev->file != NULL ) + { if ( ppdev->file != stdout ) + gp_close_printer(ppdev->file, ppdev->fname); + ppdev->file = NULL; + } + return 0; +} + +/* Free buffer space and related objects, the inverse of alloc. */ +/* Again, we break this out for resetting page dimensions. */ +private int +gdev_prn_free(gx_device *pdev) +{ if ( ppdev->ccfile != NULL ) + { clist_fclose_and_unlink(ppdev->ccfile, ppdev->ccfname); + ppdev->ccfile = NULL; + } + if ( ppdev->cbfile != NULL ) + { clist_fclose_and_unlink(ppdev->cbfile, ppdev->cbfname); + ppdev->cbfile = NULL; + } + if ( ppdev->buffer_space != 0 ) + { /* Free the buffer */ + gs_free(ppdev->buf, (uint)ppdev->buffer_space, 1, + "command list buffer(close)"); + ppdev->buf = 0; + ppdev->buffer_space = 0; + } + else + { /* Free the memory device bitmap */ + gs_free(pmemdev->base, (uint)gdev_mem_bitmap_size(pmemdev), 1, + "printer buffer(close)"); + pmemdev->base = 0; + } + pdev->std_procs = ppdev->orig_procs; + return 0; +} + +/* ------ Get/put parameters ------ */ + +/* Get parameters. Printer devices add several more parameters */ +/* to the default set. */ +int +gdev_prn_get_params(gx_device *pdev, gs_param_list *plist) +{ int code = gx_default_get_params(pdev, plist); + gs_param_string ofns; + + if ( code < 0 ) return code; + + code = (ppdev->NumCopies_set ? + param_write_int(plist, "NumCopies", &ppdev->NumCopies) : + param_write_null(plist, "NumCopies")); + if ( code < 0 ) return code; + + code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile); + if ( code < 0 ) return code; + + if ( ppdev->Duplex_set >= 0 ) + { code = + (ppdev->Duplex_set ? param_write_bool(plist, "Duplex", &ppdev->Duplex) : + param_write_null(plist, "Duplex")); + if ( code < 0 ) return code; + } + + code = param_write_long(plist, "BufferSpace", &ppdev->use_buffer_space); + if ( code < 0 ) return code; + + code = param_write_long(plist, "MaxBitmap", &ppdev->max_bitmap); + if ( code < 0 ) return code; + + ofns.data = (const byte *)ppdev->fname, + ofns.size = strlen(ppdev->fname), + ofns.persistent = false; + return param_write_string(plist, "OutputFile", &ofns); +} + +/* Put parameters. */ +int +gdev_prn_put_params(gx_device *pdev, gs_param_list *plist) +{ int ecode = 0; + int code; + const char _ds *param_name; + bool is_open = pdev->is_open; + int nci = ppdev->NumCopies; + bool ncset = ppdev->NumCopies_set; + bool oof = ppdev->OpenOutputFile; + bool duplex; + int duplex_set = -1; + int width = pdev->width; + int height = pdev->height; + long buffer_space = ppdev->use_buffer_space; + long max_bitmap = ppdev->max_bitmap; + long bsl = buffer_space; + long mbl = max_bitmap; + gs_param_string ofs; + gs_param_dict mdict; + + switch ( code = param_read_int(plist, (param_name = "NumCopies"), &nci) ) + { + case 0: + if ( nci < 0 ) + ecode = gs_error_rangecheck; + else + { ncset = true; + break; + } + goto nce; + default: + if ( (code = param_read_null(plist, param_name)) == 0 ) + { ncset = false; + break; + } + ecode = code; /* can't be 1 */ +nce: param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + switch ( code = param_read_bool(plist, (param_name = "OpenOutputFile"), &oof) ) + { + default: + ecode = code; + param_signal_error(plist, param_name, ecode); + case 0: + case 1: + break; + } + + if ( ppdev->Duplex_set >= 0 ) /* i.e., Duplex is supported */ + switch ( code = param_read_bool(plist, (param_name = "Duplex"), + &duplex) ) + { + case 0: + duplex_set = 1; + break; + default: + if ( (code = param_read_null(plist, param_name)) == 0 ) + { duplex_set = 0; + break; + } + ecode = code; + param_signal_error(plist, param_name, ecode); + case 1: + ; + } + + switch ( code = param_read_long(plist, (param_name = "BufferSpace"), &bsl) ) + { + case 0: + if ( bsl < 10000 ) + ecode = gs_error_rangecheck; + else + break; + goto bse; + default: + ecode = code; +bse: param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + switch ( code = param_read_long(plist, (param_name = "MaxBitmap"), &mbl) ) + { + case 0: + if ( mbl < 10000 ) + ecode = gs_error_rangecheck; + else + break; + goto mbe; + default: + ecode = code; +mbe: param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + switch ( code = param_read_string(plist, (param_name = "OutputFile"), &ofs) ) + { + case 0: + if ( ofs.size >= prn_fname_sizeof ) + ecode = gs_error_limitcheck; + else + { /* Check the validity of any % formats. */ + uint i; + bool pagenum = false; + for ( i = 0; i < ofs.size; ++i ) + if ( ofs.data[i] == '%' ) + { if ( i+1 < ofs.size && ofs.data[i+1] == '%' ) + continue; + if ( pagenum ) /* more than one %, */ + i = ofs.size - 1; /* force error */ + pagenum = true; +sw: if ( ++i == ofs.size ) + { ecode = gs_error_rangecheck; + goto ofe; + } + switch ( ofs.data[i] ) + { + case ' ': case '#': case '+': case '-': + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': case 'l': + goto sw; + case 'd': case 'i': case 'u': case 'o': + case 'x': case 'X': + continue; + default: + ecode = gs_error_rangecheck; + goto ofe; + } + } + break; + } + goto ofe; + default: + ecode = code; +ofe: param_signal_error(plist, param_name, ecode); + case 1: + ofs.data = 0; + break; + } + + /* Read InputAttributes and OutputAttributes just for the type */ + /* check and to indicate that they aren't undefined. */ +#define read_media(pname)\ + switch ( code = param_begin_read_dict(plist, (param_name = pname), &mdict, true) )\ + {\ + case 0:\ + param_end_read_dict(plist, pname, &mdict);\ + break;\ + default:\ + ecode = code;\ + param_signal_error(plist, param_name, ecode);\ + case 1:\ + ;\ + } + + read_media("InputAttributes"); + read_media("OutputAttributes"); + + if ( ecode < 0 ) + return ecode; + /* Prevent gx_default_put_params from closing the printer. */ + pdev->is_open = false; + code = gx_default_put_params(pdev, plist); + pdev->is_open = is_open; + if ( code < 0 ) + return code; + + ppdev->NumCopies = nci; + ppdev->NumCopies_set = ncset; + ppdev->OpenOutputFile = oof; + if ( duplex_set >= 0 ) + { ppdev->Duplex = duplex; + ppdev->Duplex_set = duplex_set; + } + /* If necessary, free and reallocate the printer memory. */ + if ( bsl != buffer_space || mbl != max_bitmap || + pdev->width != width || pdev->height != height + ) + { if ( is_open ) + gdev_prn_free(pdev); + ppdev->use_buffer_space = bsl; + ppdev->max_bitmap = mbl; + if ( is_open ) + { ecode = code = gdev_prn_alloc(pdev); + if ( code < 0 ) + { /* Try to put things back as they were. */ + ppdev->use_buffer_space = buffer_space; + ppdev->max_bitmap = max_bitmap; + gx_device_set_width_height(pdev, + width, height); + code = gdev_prn_alloc(pdev); + if ( code < 0 ) + { /* Disaster! We can't get back. */ + pdev->is_open = false; + return code; + } + return ecode; + } + } + } + if ( ofs.data != 0 && + bytes_compare(ofs.data, ofs.size, + (const byte *)ppdev->fname, strlen(ppdev->fname)) + ) + { /* Close the file if it's open. */ + if ( ppdev->file != NULL && ppdev->file != stdout ) + gp_close_printer(ppdev->file, ppdev->fname); + ppdev->file = NULL; + memcpy(ppdev->fname, ofs.data, ofs.size); + ppdev->fname[ofs.size] = 0; + } + + /* If the device is open and OpenOutputFile is true, */ + /* open the OutputFile now. (If the device isn't open, */ + /* this will happen when it is opened.) */ + if ( pdev->is_open && oof ) + { code = gdev_prn_open_printer(pdev, 1); + if ( code < 0 ) + return code; + } + + return 0; +} + +/* Put InputAttributes and OutputAttributes. */ +int +gdev_prn_input_page_size(int index, gs_param_dict *pdict, + floatp width_points, floatp height_points) +{ input_media media; + media.PageSize[0] = width_points; + media.PageSize[1] = height_points; + media.MediaColor = 0; + media.MediaWeight = 0; + media.MediaType = 0; + return gdev_prn_input_media(index, pdict, &media); +} +private int +finish_media(gs_param_list *mlist, gs_param_name key, const char *media_type) +{ int code = 0; + if ( media_type != 0 ) + { gs_param_string as; + param_string_from_string(as, media_type); + code = param_write_string(mlist, key, &as); + } + return code; +} +int +gdev_prn_input_media(int index, gs_param_dict *pdict, const input_media *pim) +{ char key[25]; + gs_param_dict mdict; + int code; + gs_param_string as; + + sprintf(key, "%d", index); + mdict.size = 4; + code = param_begin_write_dict(pdict->list, key, &mdict, false); + if ( code < 0 ) + return code; + if ( pim->PageSize[0] != 0 && pim->PageSize[1] != 0 ) + { gs_param_float_array psa; + psa.data = pim->PageSize, psa.size = 2, psa.persistent = false; + code = param_write_float_array(mdict.list, "PageSize", + &psa); + if ( code < 0 ) + return code; + } + if ( pim->MediaColor != 0 ) + { param_string_from_string(as, pim->MediaColor); + code = param_write_string(mdict.list, "MediaColor", + &as); + if ( code < 0 ) + return code; + } + if ( pim->MediaWeight != 0 ) + { /* We do the following silly thing in order to avoid */ + /* having to work around the 'const' in the arg list. */ + float weight = pim->MediaWeight; + code = param_write_float(mdict.list, "MediaWeight", + &weight); + if ( code < 0 ) + return code; + } + code = finish_media(mdict.list, "MediaType", pim->MediaType); + if ( code < 0 ) + return code; + return param_end_write_dict(pdict->list, key, &mdict); +} +int +gdev_prn_output_media(int index, gs_param_dict *pdict, const output_media *pom) +{ char key[25]; + gs_param_dict mdict; + int code; + + sprintf(key, "%d", index); + mdict.size = 4; + code = param_begin_write_dict(pdict->list, key, &mdict, false); + if ( code < 0 ) + return code; + code = finish_media(mdict.list, "OutputType", pom->OutputType); + if ( code < 0 ) + return code; + return param_end_write_dict(pdict->list, key, &mdict); +} + +/* ------ Others ------ */ + +/* Generic routine to send the page to the printer. */ +int +gdev_prn_output_page(gx_device *pdev, int num_copies, int flush) +{ int code, outcode, closecode, errcode; + + if ( num_copies > 0 ) + { code = gdev_prn_open_printer(pdev, 1); + if ( code < 0 ) + return code; + + /* Print the accumulated page description. */ + outcode = + (*ppdev->printer_procs.print_page_copies)(ppdev, + ppdev->file, + num_copies); + if (ppdev->file != NULL) + errcode = (ferror(ppdev->file) ? gs_error_ioerror : 0); + else + errcode = 0; + + closecode = gdev_prn_close_printer(pdev); + } + else + code = outcode = closecode = errcode = 0; + + if ( ppdev->buffer_space ) /* reinitialize clist for writing */ + code = (*gs_clist_device_procs.output_page)(pdev, num_copies, flush); + + if ( outcode < 0 ) + return outcode; + if ( errcode < 0 ) + return_error(errcode); + if ( closecode < 0 ) + return closecode; + return code; +} + +/* Print multiple copies of a page by calling print_page multiple times. */ +int +gx_default_print_page_copies(gx_device_printer *pdev, FILE *prn_stream, + int num_copies) +{ int i = num_copies; + int code = 0; + while ( code >= 0 && i-- > 0 ) + code = (*pdev->printer_procs.print_page)(pdev, prn_stream); + return code; +} + +/* ---------------- Driver services ---------------- */ + +/* Return the number of scan lines that should actually be passed */ +/* to the device. */ +int +gdev_prn_print_scan_lines(gx_device *pdev) +{ int height = pdev->height; + gs_matrix imat; + float yscale; + int top, bottom, offset, end; + + (*dev_proc(pdev, get_initial_matrix))(pdev, &imat); + yscale = imat.yy * 72.0; /* Y dpi, may be negative */ + top = (int)(dev_t_margin(pdev) * yscale); + bottom = (int)(dev_b_margin(pdev) * yscale); + offset = (int)(dev_y_offset(pdev) * yscale); + if ( yscale < 0 ) + { /* Y=0 is top of page */ + end = -offset + height + bottom; + } + else + { /* Y=0 is bottom of page */ + end = offset + height - top; + } + return min(height, end); +} + +/* Open the current page for printing. */ +int +gdev_prn_open_printer(gx_device *pdev, int binary_mode) +{ char *fname = ppdev->fname; + char pfname[prn_fname_sizeof + 20]; + char *fchar = fname; + long count1 = ppdev->PageCount + 1; + + while ( (fchar = strchr(fchar, '%')) != NULL ) + { if ( *++fchar == '%' ) + { ++fchar; + continue; + } + while ( !isalpha(*fchar) ) + ++fchar; + sprintf(pfname, fname, + (*fchar == 'l' ? count1 : (int)count1)); + fname = pfname; + break; + } + if ( ppdev->file == NULL ) + { if ( !strcmp(fname, "-") ) + ppdev->file = stdout; + else + { ppdev->file = gp_open_printer(fname, binary_mode); + if ( ppdev->file == NULL ) + return_error(gs_error_invalidfileaccess); + } + ppdev->file_is_new = true; + } + else + ppdev->file_is_new = false; + return 0; +} + +/* Copy a scan line from the buffer to the printer. */ +int +gdev_prn_get_bits(gx_device_printer *pdev, int y, byte *str, byte **actual_data) +{ int code = (*dev_proc(pdev, get_bits))((gx_device *)pdev, y, str, actual_data); + uint line_size = gdev_prn_raster(pdev); + int last_bits = -(pdev->width * pdev->color_info.depth) & 7; + if ( code < 0 ) return code; + if ( last_bits != 0 ) + { byte *dest = (actual_data != 0 ? *actual_data : str); + dest[line_size - 1] &= 0xff << last_bits; + } + return 0; +} +/* Copy scan lines to a buffer. Return the number of scan lines, */ +/* or <0 if error. */ +int +gdev_prn_copy_scan_lines(gx_device_printer *pdev, int y, byte *str, uint size) +{ uint line_size = gdev_prn_raster(pdev); + int count = size / line_size; + int i; + byte *dest = str; + count = min(count, pdev->height - y); + for ( i = 0; i < count; i++, dest += line_size ) + { int code = gdev_prn_get_bits(pdev, y + i, dest, NULL); + if ( code < 0 ) return code; + } + return count; +} + +/* Close the current page. */ +int +gdev_prn_close_printer(gx_device *pdev) +{ if ( strchr(ppdev->fname, '%') ) /* file per page */ + { gp_close_printer(ppdev->file, ppdev->fname); + ppdev->file = NULL; + } + return 0; +} diff --git a/pstoraster/gdevprn.h b/pstoraster/gdevprn.h new file mode 100644 index 0000000000..5206d2a2e0 --- /dev/null +++ b/pstoraster/gdevprn.h @@ -0,0 +1,418 @@ +/* + Copyright 1993-1999 by Easy Software Products. + Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gdevprn.h */ +/* Common header file for memory-buffered printers */ + +#ifndef gdevprn_INCLUDED +# define gdevprn_INCLUDED + +#include "memory_.h" +#include "string_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsmatrix.h" /* for gxdevice.h */ +#include "gsutil.h" /* for memflip8x8 */ +#include "gxdevice.h" +#include "gxdevmem.h" +#include "gxclist.h" +#include "gsparam.h" + +/* Define the page size parameters. */ +/* U.S. letter paper (8.5" x 11"). */ +#define DEFAULT_WIDTH_10THS_US_LETTER 85 +#define DEFAULT_HEIGHT_10THS_US_LETTER 110 +/* A4 paper (210mm x 297mm). The dimensions are off by a few mm.... */ +#define DEFAULT_WIDTH_10THS_A4 83 +#define DEFAULT_HEIGHT_10THS_A4 117 +/* Choose a default. A4 may be set in the makefile. */ +#ifdef A4 +# define DEFAULT_WIDTH_10THS DEFAULT_WIDTH_10THS_A4 +# define DEFAULT_HEIGHT_10THS DEFAULT_HEIGHT_10THS_A4 +#else +# define DEFAULT_WIDTH_10THS DEFAULT_WIDTH_10THS_US_LETTER +# define DEFAULT_HEIGHT_10THS DEFAULT_HEIGHT_10THS_US_LETTER +#endif + +/* + * Define the parameters for the printer rendering method. + * If the entire bitmap fits in PRN_MAX_BITMAP, and there is at least + * PRN_MIN_MEMORY_LEFT memory left after allocating it, render in RAM, + * otherwise use a command list with a size of PRN_BUFFER_SPACE. + * (These are parameters that can be changed by a client program.) + */ +/* Define parameters for machines with little dinky RAMs.... */ +#define PRN_MAX_BITMAP_SMALL 32000 +#define PRN_BUFFER_SPACE_SMALL 25000 +#define PRN_MIN_MEMORY_LEFT_SMALL 32000 +/* Define parameters for machines with great big hulking RAMs.... */ +#define PRN_MAX_BITMAP_LARGE 10000000L +#define PRN_BUFFER_SPACE_LARGE 1000000L +#define PRN_MIN_MEMORY_LEFT_LARGE 500000L +/* Define parameters valid on all machines. */ +#define PRN_MIN_BUFFER_SPACE 10000 /* give up if less than this */ +/* Now define conditional parameters. */ +#if arch_small_memory +# define PRN_MAX_BITMAP PRN_MAX_BITMAP_SMALL +# define PRN_BUFFER_SPACE PRN_BUFFER_SPACE_SMALL +# define PRN_MIN_MEMORY_LEFT PRN_MIN_MEMORY_LEFT_SMALL +#else +/****** These should really be conditional on gs_debug_c('.') if + ****** DEBUG is defined, but they're used in static initializers, + ****** so we can't do it. + ******/ +# if 0 /****** # ifdef DEBUG ******/ +# define PRN_MAX_BITMAP\ + (gs_debug_c('.') ? PRN_MAX_BITMAP_SMALL : PRN_MAX_BITMAP_LARGE) +# define PRN_BUFFER_SPACE\ + (gs_debug_c('.') ? PRN_BUFFER_SPACE_SMALL : PRN_BUFFER_SPACE_LARGE) +# define PRN_MIN_MEMORY_LEFT\ + (gs_debug_c('.') ? PRN_MIN_MEMORY_LEFT_SMALL : PRN_MIN_MEMORY_LEFT_LARGE) +# else +# define PRN_MAX_BITMAP PRN_MAX_BITMAP_LARGE +# define PRN_BUFFER_SPACE PRN_BUFFER_SPACE_LARGE +# define PRN_MIN_MEMORY_LEFT PRN_MIN_MEMORY_LEFT_LARGE +# endif +#endif + +/* Define the abstract type for a printer device. */ +typedef struct gx_device_printer_s gx_device_printer; + +/* + * Define the special procedures for band devices. + */ +typedef struct gx_printer_device_procs_s { + + /* + * Print the page on the output file. Required only for devices + * where output_page is gdev_prn_output_page; ignored for other + * devices. + */ + +#define dev_proc_print_page(proc)\ + int proc(P2(gx_device_printer *, FILE *)) + dev_proc_print_page((*print_page)); + + /* Print the page on the output file, with a given # of copies. */ + +#define dev_proc_print_page_copies(proc)\ + int proc(P3(gx_device_printer *, FILE *, int)) + dev_proc_print_page_copies((*print_page_copies)); + + /* Initialize the memory device for a page or a band. */ + /* (The macro definition is in gxdevice.h.) */ + + dev_proc_make_buffer_device((*make_buffer_device)); + +} gx_printer_device_procs; + +/* ------ Printer device definition ------ */ + +/* Structure for generic printer devices. */ +/* This must be preceded by gx_device_common. */ +/* Printer devices are actually a union of a memory device */ +/* and a clist device, plus some additional state. */ +#define prn_fname_sizeof 80 +#define gx_prn_device_common\ + byte skip[max(sizeof(gx_device_memory), sizeof(gx_device_clist)) -\ + sizeof(gx_device) + sizeof(double) /* padding */];\ + gx_printer_device_procs printer_procs;\ + /* ------ The following items must be set before ------ */\ + /* ------ calling the device open routine. ------ */\ + long max_bitmap; /* max size of non-buffered bitmap */\ + long use_buffer_space; /* space to use for buffer */\ + char fname[prn_fname_sizeof]; /* output file name */\ + /* ------ End of preset items ------ */\ + int NumCopies;\ + bool NumCopies_set;\ + bool OpenOutputFile;\ + bool Duplex;\ + int Duplex_set; /* -1 = not supported */\ + bool file_is_new; /* true iff file just opened */\ + FILE *file; /* output file */\ + char ccfname[60]; /* clist file name */\ + clist_file_ptr ccfile; /* command list scratch file */\ + char cbfname[60]; /* clist block file name */\ + clist_file_ptr cbfile; /* command list block scratch file */\ + long buffer_space; /* amount of space for clist buffer, */\ + /* 0 means not using clist */\ + byte *buf; /* buffer for rendering */\ + gx_device_procs orig_procs /* original (std_)procs */ + +/* The device descriptor */ +struct gx_device_printer_s { + gx_device_common; + gx_prn_device_common; +}; + +/* Macro for casting gx_device argument */ +#define prn_dev ((gx_device_printer *)dev) + +/* Define a typedef for the sake of ansi2knr. */ +typedef dev_proc_print_page((*dev_proc_print_page_t)); + +/* Standard device procedures for printers */ +dev_proc_open_device(gdev_prn_open); +dev_proc_output_page(gdev_prn_output_page); +dev_proc_close_device(gdev_prn_close); +#define gdev_prn_map_rgb_color gx_default_b_w_map_rgb_color +#define gdev_prn_map_color_rgb gx_default_b_w_map_color_rgb +dev_proc_get_params(gdev_prn_get_params); +dev_proc_put_params(gdev_prn_put_params); + +/* Macro for generating procedure table */ +#define prn_procs(p_open, p_output_page, p_close)\ + prn_color_procs(p_open, p_output_page, p_close, gdev_prn_map_rgb_color, gdev_prn_map_color_rgb) +#define prn_params_procs(p_open, p_output_page, p_close, p_get_params, p_put_params)\ + prn_color_params_procs(p_open, p_output_page, p_close, gdev_prn_map_rgb_color, gdev_prn_map_color_rgb, p_get_params, p_put_params) +#define prn_color_procs(p_open, p_output_page, p_close, p_map_rgb_color, p_map_color_rgb)\ + prn_color_params_procs(p_open, p_output_page, p_close, p_map_rgb_color, p_map_color_rgb, gdev_prn_get_params, gdev_prn_put_params) +/* See gdev_prn_open for explanation of the NULLs below. */ +#define prn_color_params_procs(p_open, p_output_page, p_close, p_map_rgb_color, p_map_color_rgb, p_get_params, p_put_params) {\ + p_open,\ + NULL, /* get_initial_matrix */\ + NULL, /* sync_output */\ + p_output_page,\ + p_close,\ + p_map_rgb_color,\ + p_map_color_rgb,\ + NULL, /* fill_rectangle */\ + NULL, /* tile_rectangle */\ + NULL, /* copy_mono */\ + NULL, /* copy_color */\ + NULL, /* draw_line */\ + NULL, /* get_bits */\ + p_get_params,\ + p_put_params,\ + NULL, /* map_cmyk_color */\ + NULL, /* get_xfont_procs */\ + NULL, /* get_xfont_device */\ + NULL, /* map_rgb_alpha_color */\ + gx_page_device_get_page_device,\ + NULL, /* get_alpha_bits */\ + NULL, /* copy_alpha */\ + NULL, /* get_band */\ + NULL, /* copy_rop */\ + NULL, /* fill_path */\ + NULL, /* stroke_path */\ + NULL, /* fill_mask */\ + NULL, /* fill_trapezoid */\ + NULL, /* fill_parallelogram */\ + NULL, /* fill_triangle */\ + NULL, /* draw_thin_line */\ + NULL, /* begin_image */\ + NULL, /* image_data */\ + NULL, /* end_image */\ + NULL, /* strip_tile_rectangle */\ + NULL /* strip_copy_rop */\ +} + +/* The standard printer device procedures */ +/* (using gdev_prn_open/output_page/close). */ +extern gx_device_procs prn_std_procs; + +/* + * Define macros for generating the device structure, + * analogous to the std_device_body macros in gxdevice.h + * Note that the macros are broken up so as to be usable for devices that + * add further initialized state to the printer device. + * + * The 'margin' values provided here specify the unimageable region + * around the edges of the page (in inches), and the left and top margins + * also specify the displacement of the device (0,0) point from the + * upper left corner. We should provide macros that allow specifying + * all 6 values independently, but we don't yet. + */ +#define prn_device_body_rest_(print_page)\ + { 0 }, /* std_procs */\ + { 0 }, /* skip */\ + { print_page,\ + gx_default_print_page_copies,\ + gx_default_make_buffer_device\ + },\ + PRN_MAX_BITMAP,\ + PRN_BUFFER_SPACE,\ + { 0 }, /* fname */\ + 1, 0/*false*/, /* NumCopies[_set] */\ + 0/*false*/, /* OpenOutputFile */\ + 0/*false*/, -1, /* Duplex[_set] */\ + 0/*false*/, 0, { 0 }, 0, { 0 }, 0, 0, 0, { 0 } /* ... orig_procs */ + +/* The Sun cc compiler won't allow \ within a macro argument list. */ +/* This accounts for the short parameter names here and below. */ +#define prn_device_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page)\ + std_device_full_body(dtype, &procs, dname,\ + (int)((long)w10 * xdpi / 10),\ + (int)((long)h10 * ydpi / 10),\ + xdpi, ydpi,\ + ncomp, depth, mg, mc, dg, dc,\ + -(lo) * (xdpi), -(to) * (ydpi),\ + (lm) * 72.0, (bm) * 72.0,\ + (rm) * 72.0, (tm) * 72.0\ + ),\ + prn_device_body_rest_(print_page) + +#define prn_device_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page)\ + prn_device_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi,\ + lm, tm, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_page) + +#define prn_device_body_copies(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_pages)\ + std_device_full_body(dtype, &procs, dname,\ + (int)((long)w10 * xdpi / 10),\ + (int)((long)h10 * ydpi / 10),\ + xdpi, ydpi,\ + ncomp, depth, mg, mc, dg, dc,\ + -(lm) * (xdpi), -(tm) * (ydpi),\ + (lm) * 72.0, (bm) * 72.0,\ + (rm) * 72.0, (tm) * 72.0\ + ),\ + { 0 }, /* std_procs */\ + { 0 }, /* skip */\ + { NULL,\ + print_pages,\ + gx_default_make_buffer_device\ + },\ + PRN_MAX_BITMAP,\ + PRN_BUFFER_SPACE,\ + { 0 }, /* fname */\ + 1, 0/*false*/, /* NumCopies[_set] */\ + 0/*false*/, /* OpenOutputFile */\ + 0/*false*/, -1, /* Duplex[_set] */\ + 0/*false*/, 0, { 0 }, 0, { 0 }, 0, 0, 0, { 0 } /* ... orig_procs */ + +#define prn_device_std_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, color_bits, print_page)\ + std_device_std_color_full_body(dtype, &procs, dname,\ + (int)((long)w10 * xdpi / 10),\ + (int)((long)h10 * ydpi / 10),\ + xdpi, ydpi, color_bits,\ + -(lo) * (xdpi), -(to) * (ydpi),\ + (lm) * 72.0, (bm) * 72.0,\ + (rm) * 72.0, (tm) * 72.0\ + ),\ + prn_device_body_rest_(print_page) + +#define prn_device_std_body(dtype, procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, color_bits, print_page)\ + prn_device_std_margins_body(dtype, procs, dname, w10, h10, xdpi, ydpi,\ + lm, tm, lm, bm, rm, tm, color_bits, print_page) + +#define prn_device_margins(procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, color_bits, print_page)\ +{ prn_device_std_margins_body(gx_device_printer, procs, dname,\ + w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, color_bits, print_page)\ +} + +#define prn_device(procs, dname, w10, h10, xdpi, ydpi, lm, bm, rm, tm, color_bits, print_page)\ + prn_device_margins(procs, dname, w10, h10, xdpi, ydpi,\ + lm, tm, lm, bm, rm, tm, color_bits, print_page)\ + +/* ------ Utilities ------ */ +/* These are defined in gdevprn.c. */ + +int gdev_prn_open_printer(P2(gx_device *dev, int binary_mode)); +#define gdev_prn_file_is_new(pdev) ((pdev)->file_is_new) +#define gdev_prn_raster(pdev) gx_device_raster((gx_device *)(pdev), 0) +int gdev_prn_get_bits(P4(gx_device_printer *, int, byte *, byte **)); +int gdev_prn_copy_scan_lines(P4(gx_device_printer *, int, byte *, uint)); +int gdev_prn_close_printer(P1(gx_device *)); + +/* Define the InputAttributes and OutputAttributes of a device. */ +/* The device get_params procedure would call these. */ + +typedef struct input_media_s { + float PageSize[2]; + const char *MediaColor; + float MediaWeight; + const char *MediaType; +} input_media; +#define gdev_prn_begin_input_media(plist, pdict, count)\ + ((pdict)->size = (count),\ + param_begin_write_dict(plist, "InputAttributes", pdict, true)) +int gdev_prn_input_page_size(P4(int index, gs_param_dict *pdict, + floatp width_points, floatp height_points)); +int gdev_prn_input_media(P3(int index, gs_param_dict *pdict, + const input_media *pim)); +#define gdev_prn_end_input_media(plist, pdict)\ + param_end_write_dict(plist, "InputAttributes", pdict) + +typedef struct output_media_s { + const char *OutputType; +} output_media; +#define gdev_prn_begin_output_media(plist, pdict, count)\ + ((pdict)->size = (count),\ + param_begin_write_dict(plist, "OutputAttributes", pdict, true)) +int gdev_prn_output_media(P3(int index, gs_param_dict *pdict, + const output_media *pom)); +#define gdev_prn_end_output_media(plist, pdict)\ + param_end_write_dict(plist, "OutputAttributes", pdict) + +/* The default print_page_copies procedure just calls print_page */ +/* the given number of times. */ +dev_proc_print_page_copies(gx_default_print_page_copies); + +/* Define the number of scan lines that should actually be passed */ +/* to the device. */ +int gdev_prn_print_scan_lines(P1(gx_device *)); + +/* BACKWARD COMPATIBILITY */ +#define dev_print_scan_lines(dev)\ + gdev_prn_print_scan_lines((gx_device *)(dev)) +#define gdev_mem_bytes_per_scan_line(dev)\ + gdev_prn_raster((gx_device_printer *)(dev)) +#define gdev_prn_transpose_8x8(inp,ils,outp,ols)\ + memflip8x8(inp,ils,outp,ols) + +/* ------ Printer device types ------ */ +/**************** THE FOLLOWING CODE IS NOT USED YET. ****************/ + +#if 0 /**************** VMS linker gets upset ****************/ +extern_st(st_prn_device); +#endif +int gdev_prn_initialize(P3(gx_device *, const char _ds *, dev_proc_print_page((*)))); +void gdev_prn_init_color(P4(gx_device *, int, dev_proc_map_rgb_color((*)), dev_proc_map_color_rgb((*)))); + +#define prn_device_type(dtname, initproc, pageproc)\ +private dev_proc_print_page(pageproc);\ +device_type(dtname, st_prn_device, initproc) + +/****** FOLLOWING SHOULD CHECK __PROTOTYPES__ ******/ +#define prn_device_type_mono(dtname, dname, initproc, pageproc)\ +private dev_proc_print_page(pageproc);\ +private int \ +initproc(gx_device *dev)\ +{ return gdev_prn_initialize(dev, dname, pageproc);\ +}\ +device_type(dtname, st_prn_device, initproc) + +/****** DITTO ******/ +#define prn_device_type_color(dtname, dname, depth, initproc, pageproc, rcproc, crproc)\ +private dev_proc_print_page(pageproc);\ +private int \ +initproc(gx_device *dev)\ +{ int code = gdev_prn_initialize(dev, dname, pageproc);\ + gdev_prn_init_color(dev, depth, rcproc, crproc);\ + return code;\ +}\ +device_type(dtname, st_prn_device, initproc) + +#endif /* gdevprn_INCLUDED */ diff --git a/pstoraster/genarch.c b/pstoraster/genarch.c new file mode 100644 index 0000000000..855fcdbf3f --- /dev/null +++ b/pstoraster/genarch.c @@ -0,0 +1,131 @@ +/* Copyright (C) 1989, 1995 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* genarch.c */ +/* Generate a header file (arch.h) with parameters */ +/* reflecting the machine architecture and compiler characteristics. */ + +#include "stdpre.h" +#include +#include "iref.h" + +/* We should write the result on stdout, but the original Turbo C 'make' */ +/* can't handle output redirection (sigh). */ + +main(int argc, char *argv[]) +{ char *fname = argv[1]; + long one = 1; +#define ffs_strlen 16 + char *ffs = "ffffffffffffffff"; + struct { char c; short s; } ss; + struct { char c; int i; } si; + struct { char c; long l; } sl; + struct { char c; char *p; } sp; + struct { char c; float f; } sf; + struct { char c; double d; } sd; + struct { char c; ref r; } sr; + static int log2s[17] = {0,0,1,0,2,0,0,0,3,0,0,0,0,0,0,0,4}; + long lm1 = -1; + long lr1 = lm1 >> 1, lr2 = lm1 >> 2; + unsigned long um1 = ~(unsigned long)0; + int im1 = -1; + int ir1 = im1 >> 1, ir2 = im1 >> 2; + union { long l; char *p; } pl0, pl1; + int ars; + int lwidth = size_of(long) * 8; + union { float f; int i; long l; } f0, f1, fm1; + FILE *f = fopen(fname, "w"); + if ( f == NULL ) + { fprintf(stderr, "genarch.c: can't open %s for writing\n", fname); + return exit_FAILED; + } + fprintf(f, "/* Parameters derived from machine and compiler architecture */\n"); +#define S(str) fprintf(f, "\n\t%s\n\n", str) + +S("/* ---------------- Scalar alignments ---------------- */"); + +#define offset(s, e) (int)((char *)&s.e - (char *)&s) + fprintf(f, "#define arch_align_short_mod %d\n", offset(ss, s)); + fprintf(f, "#define arch_align_int_mod %d\n", offset(si, i)); + fprintf(f, "#define arch_align_long_mod %d\n", offset(sl, l)); + fprintf(f, "#define arch_align_ptr_mod %d\n", offset(sp, p)); + fprintf(f, "#define arch_align_float_mod %d\n", offset(sf, f)); + fprintf(f, "#define arch_align_double_mod %d\n", offset(sd, d)); + fprintf(f, "#define arch_align_ref_mod %d\n", offset(sr, r)); +#undef offset + +S("/* ---------------- Scalar sizes ---------------- */"); + + fprintf(f, "#define arch_log2_sizeof_short %d\n", log2s[size_of(short)]); + fprintf(f, "#define arch_log2_sizeof_int %d\n", log2s[size_of(int)]); + fprintf(f, "#define arch_log2_sizeof_long %d\n", log2s[size_of(long)]); + fprintf(f, "#define arch_sizeof_ds_ptr %d\n", size_of(char _ds *)); + fprintf(f, "#define arch_sizeof_ptr %d\n", size_of(char *)); + fprintf(f, "#define arch_sizeof_float %d\n", size_of(float)); + fprintf(f, "#define arch_sizeof_double %d\n", size_of(double)); + fprintf(f, "#define arch_sizeof_ref %d\n", size_of(ref)); + +S("/* ---------------- Unsigned max values ---------------- */"); + +#define pmax(str, typ, tstr, l)\ + fprintf(f, "#define arch_max_%s ((%s)0x%s%s + (%s)0)\n",\ + str, tstr, ffs + ffs_strlen - size_of(typ) * 2, l, tstr) + pmax("uchar", unsigned char, "unsigned char", ""); + pmax("ushort", unsigned short, "unsigned short", ""); + pmax("uint", unsigned int, "unsigned int", ""); + pmax("ulong", unsigned long, "unsigned long", "L"); +#undef pmax + +S("/* ---------------- Miscellaneous ---------------- */"); + + fprintf(f, "#define arch_is_big_endian %d\n", 1 - *(char *)&one); + pl0.l = 0; + pl1.l = -1; + fprintf(f, "#define arch_ptrs_are_signed %d\n", + (pl1.p < pl0.p)); + f0.f = 0.0, f1.f = 1.0, fm1.f = -1.0; + /* We have to test the size dynamically here, */ + /* because the preprocessor can't evaluate sizeof. */ + fprintf(f, "#define arch_floats_are_IEEE %d\n", + ((size_of(float) == size_of(int) ? + f0.i == 0 && f1.i == (int)0x3f800000 && fm1.i == (int)0xbf800000 : + f0.l == 0 && f1.l == 0x3f800000L && fm1.l == 0xbf800000L) + ? 1 : 0)); + /* There are three cases for arithmetic right shift: */ + /* always correct, correct except for right-shifting a long by 1 */ + /* (a bug in some versions of the Turbo C compiler), and */ + /* never correct. */ + ars = (lr2 != -1 || ir1 != -1 || ir2 != -1 ? 0 : + lr1 != -1 ? 1 : /* Turbo C problem */ + 2); + fprintf(f, "#define arch_arith_rshift %d\n", ars); + /* Some machines can't handle a variable shift by */ + /* the full width of a long. */ + fprintf(f, "#define arch_can_shift_full_long %d\n", + um1 >> lwidth == 0); + +/* ---------------- Done. ---------------- */ + + fclose(f); + return exit_OK; +} diff --git a/pstoraster/ghost.h b/pstoraster/ghost.h new file mode 100644 index 0000000000..fbb6db087d --- /dev/null +++ b/pstoraster/ghost.h @@ -0,0 +1,27 @@ +/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* ghost.h */ +/* Common definitions for interpreter */ +#include "gx.h" +#include "iref.h" diff --git a/pstoraster/gp.h b/pstoraster/gp.h new file mode 100644 index 0000000000..05e9d0fccd --- /dev/null +++ b/pstoraster/gp.h @@ -0,0 +1,201 @@ +/* Copyright (C) 1991, 1995 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gp.h */ +/* Interface to platform-specific routines */ +/* Requires gsmemory.h, gstypes.h */ + +/* + * This file defines the interface to ***ALL*** platform-specific routines. + * The routines are implemented in a gp_*.c file specific to each platform. + * We try very hard to keep this list short! + */ + +/* ------ Initialization/termination ------ */ + +/* + * This routine is called early in the initialization. + * It should do as little as possible. In particular, it should not + * do things like open display connections: that is the responsibility + * of the display device driver. + */ +void gp_init(P0()); + +/* + * This routine is called just before the program exits (normally or + * abnormally). It too should do as little as possible. + */ +void gp_exit(P2(int exit_status, int code)); + +/* + * Exit the program. Normally this just calls the `exit' library procedure, + * but it does something different on a few platforms. + */ +void gp_do_exit(P1(int exit_status)); + +/* ------ Miscellaneous ------ */ + +/* + * Get the string corresponding to an OS error number. + * If no string is available, return NULL. The caller may assume + * the string is allocated statically and permanently. + */ +const char *gp_strerror(P1(int)); + +/* ------ Date and time ------ */ + +/* + * Read the current time (in seconds since an implementation-defined epoch) + * into ptm[0], and fraction (in nanoseconds) into ptm[1]. + */ +void gp_get_realtime(P1(long ptm[2])); + +/* + * Read the current user CPU time (in seconds) into ptm[0], + * and fraction (in nanoseconds) into ptm[1]. + */ +void gp_get_usertime(P1(long ptm[2])); + +/* ------ Screen management ------ */ + +/* + * The following routines are only relevant in a single-window environment + * such as a PC; on platforms with window systems, the 'make current' + * routines do nothing. + */ + +#ifndef gx_device_DEFINED +# define gx_device_DEFINED +typedef struct gx_device_s gx_device; +#endif + +/* Initialize the console. */ +void gp_init_console(P0()); + +/* Write a string to the console. */ +void gp_console_puts(P2(const char *, uint)); + +/* Make the console current on the screen. */ +int gp_make_console_current(P1(gx_device *)); + +/* Make the graphics current on the screen. */ +int gp_make_graphics_current(P1(gx_device *)); + +/* + * The following are only relevant for X Windows. + */ + +/* Get the environment variable that specifies the display to use. */ +const char *gp_getenv_display(P0()); + +/* ------ Printer accessing ------ */ + +/* + * Open a connection to a printer. A null file name means use the + * standard printer connected to the machine, if any. + * If possible, support "|command" for opening an output pipe. + * Return NULL if the connection could not be opened. + */ +FILE *gp_open_printer(P2(char *fname, int binary_mode)); + +/* Close the connection to the printer. */ +void gp_close_printer(P2(FILE *pfile, const char *fname)); + +/* ------ File naming and accessing ------ */ + +/* Define the character used for separating file names in a list. */ +extern const char gp_file_name_list_separator; + +/* Define the default scratch file name prefix. */ +extern const char gp_scratch_file_name_prefix[]; + +/* Define the name of the null output file. */ +extern const char gp_null_file_name[]; + +/* Define the name that designates the current directory. */ +extern const char gp_current_directory_name[]; + +/* Define the string to be concatenated with the file mode */ +/* for opening files without end-of-line conversion. */ +/* This is always either "" or "b". */ +extern const char gp_fmode_binary_suffix[]; +/* Define the file modes for binary reading or writing. */ +/* (This is just a convenience: they are "r" or "w" + the suffix.) */ +extern const char gp_fmode_rb[]; +extern const char gp_fmode_wb[]; + +/* Create and open a scratch file with a given name prefix. */ +/* Write the actual file name at fname. */ +FILE *gp_open_scratch_file(P3(const char *prefix, char *fname, + const char *mode)); + +/* Open a file with the given name, as a stream of uninterpreted bytes. */ +FILE *gp_fopen(P2(const char *fname, const char *mode)); + +/* Answer whether a file name contains a directory/device specification, */ +/* i.e. is absolute (not directory- or device-relative). */ +bool gp_file_name_is_absolute(P2(const char *fname, uint len)); + +/* Answer the string to be used for combining a directory/device prefix */ +/* with a base file name. The file name is known to not be absolute. */ +const char *gp_file_name_concat_string(P4(const char *prefix, uint plen, + const char *fname, uint len)); + +/* ------ File enumeration ------ */ + +#ifndef file_enum_DEFINED /* also defined in iodev.h */ +# define file_enum_DEFINED +struct file_enum_s; /* opaque to client, defined by implementor */ +typedef struct file_enum_s file_enum; +#endif + +/* + * Begin an enumeration. pat is a C string that may contain *s or ?s. + * The implementor should copy the string to a safe place. + * If the operating system doesn't support correct, arbitrarily placed + * *s and ?s, the implementation should modify the string so that it + * will return a conservative superset of the request, and then use + * the string_match procedure to select the desired subset. E.g., if the + * OS doesn't implement ? (single-character wild card), any consecutive + * string of ?s should be interpreted as *. Note that \ can appear in + * the pattern also, as a quoting character. + */ +file_enum *gp_enumerate_files_init(P3(const char *pat, uint patlen, + gs_memory_t *memory)); + +/* + * Return the next file name in the enumeration. The client passes in + * a scratch string and a max length. If the name of the next file fits, + * the procedure returns the length. If it doesn't fit, the procedure + * returns max length +1. If there are no more files, the procedure + * returns -1. + */ +uint gp_enumerate_files_next(P3(file_enum *pfen, char *ptr, uint maxlen)); + +/* + * Clean up a file enumeration. This is only called to abandon + * an enumeration partway through: ...next should do it if there are + * no more files to enumerate. This should deallocate the file_enum + * structure and any subsidiary structures, strings, buffers, etc. + */ +void gp_enumerate_files_close(P1(file_enum *pfen)); diff --git a/pstoraster/gp_nofb.c b/pstoraster/gp_nofb.c new file mode 100644 index 0000000000..76e681633c --- /dev/null +++ b/pstoraster/gp_nofb.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1993 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gp_nofb.c */ +/* Dummy routines for Ghostscript platforms with no frame buffer management */ +#include "gx.h" +#include "gp.h" +#include "gxdevice.h" + +/* ------ Screen management ------ */ + +/* Initialize the console. */ +void +gp_init_console(void) +{ +} + +/* Write a string to the console. */ +void +gp_console_puts(const char *str, uint size) +{ fwrite(str, 1, size, stdout); +} + +/* Make the console current on the screen. */ +int +gp_make_console_current(gx_device *dev) +{ return 0; +} + +/* Make the graphics current on the screen. */ +int +gp_make_graphics_current(gx_device *dev) +{ return 0; +} diff --git a/pstoraster/gp_unifn.c b/pstoraster/gp_unifn.c new file mode 100644 index 0000000000..10d55a5831 --- /dev/null +++ b/pstoraster/gp_unifn.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gp_unifn.c */ +/* Unix-like file name syntax platform routines for Ghostscript */ +#include "gx.h" +#include "gp.h" + +/* Define the character used for separating file names in a list. */ +const char gp_file_name_list_separator = ':'; + +/* Define the string to be concatenated with the file mode */ +/* for opening files without end-of-line conversion. */ +const char gp_fmode_binary_suffix[] = ""; +/* Define the file modes for binary reading or writing. */ +const char gp_fmode_rb[] = "r"; +const char gp_fmode_wb[] = "w"; + +/* Answer whether a file name contains a directory/device specification, */ +/* i.e. is absolute (not directory- or device-relative). */ +bool +gp_file_name_is_absolute(const char *fname, unsigned len) +{ /* A file name is absolute if it starts with a 0 or more .s */ + /* followed by a /. */ + while ( len && *fname == '.' ) + ++fname, --len; + return (len && *fname == '/'); +} + +/* Answer the string to be used for combining a directory/device prefix */ +/* with a base file name. The file name is known to not be absolute. */ +const char * +gp_file_name_concat_string(const char *prefix, unsigned plen, + const char *fname, unsigned len) +{ if ( plen > 0 && prefix[plen - 1] == '/' ) + return ""; + return "/"; +} diff --git a/pstoraster/gp_unifs.c b/pstoraster/gp_unifs.c new file mode 100644 index 0000000000..b2251519f2 --- /dev/null +++ b/pstoraster/gp_unifs.c @@ -0,0 +1,424 @@ +/* Copyright (C) 1993, 1995 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gp_unifs.c */ +/* "Unix-like" file system platform routines for Ghostscript */ +#include "memory_.h" +#include "string_.h" +#include "gx.h" +#include "gp.h" +#include "gsstruct.h" +#include "gsutil.h" /* for string_match */ +#include "stat_.h" +#include "dirent_.h" +#include /* for MAXPATHLEN */ + +/* Some systems (Interactive for example) don't define MAXPATHLEN, + * so we define it here. (This probably should be done via a Config-Script.) + */ + +#ifndef MAXPATHLEN +# define MAXPATHLEN 1024 +#endif + +/* Library routines not declared in a standard header */ +extern char *getenv(P1(const char *)); +extern char *mktemp(P1(char *)); + +/* ------ File naming and accessing ------ */ + +/* Define the default scratch file name prefix. */ +const char gp_scratch_file_name_prefix[] = "gs_"; + +/* Define the name of the null output file. */ +const char gp_null_file_name[] = "/dev/null"; + +/* Define the name that designates the current directory. */ +const char gp_current_directory_name[] = "."; + +/* Create and open a scratch file with a given name prefix. */ +/* Write the actual file name at fname. */ +FILE * +gp_open_scratch_file(const char *prefix, char *fname, const char *mode) +{ char *temp; + if ( (temp = getenv("TMPDIR")) == NULL ) + strcpy(fname, "/var/tmp/"); + else + { strcpy(fname, temp); + if ( strlen(fname) != 0 && fname[strlen(fname) - 1] != '/' ) + strcat(fname, "/"); + } + strcat(fname, prefix); + /* Prevent trailing X's in path from being converted by mktemp. */ + if ( *fname != 0 && fname[strlen(fname) - 1] == 'X' ) + strcat(fname, "-"); + strcat(fname, "XXXXXX"); + mktemp(fname); + return fopen(fname, mode); +} + +/* Open a file with the given name, as a stream of uninterpreted bytes. */ +FILE * +gp_fopen(const char *fname, const char *mode) +{ return fopen(fname, mode); +} + +/* ------ File enumeration ------ */ + +/* Thanks to Fritz Elfert (Fritz_Elfert@wue.maus.de) for */ +/* the original version of the following code, and Richard Mlynarik */ +/* (mly@adoc.xerox.com) for an improved version. */ + +typedef struct dirstack_s dirstack; +struct dirstack_s { + dirstack *next; + DIR *entry; +}; +gs_private_st_ptrs1(st_dirstack, dirstack, "dirstack", + dirstack_enum_ptrs, dirstack_reloc_ptrs, next); + +struct file_enum_s { + DIR *dirp; /* pointer to current open directory */ + char *pattern; /* original pattern */ + char *work; /* current path */ + int worklen; /* strlen (work) */ + dirstack *dstack; /* directory stack */ + int patlen; + int pathead; /* how much of pattern to consider + * when listing files in current directory */ + bool first_time; + gs_memory_t *memory; +}; +gs_private_st_ptrs3(st_file_enum, struct file_enum_s, "file_enum", + file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern, work, dstack); + +/* Private procedures */ + +/* Do a wild-card match. */ +#ifdef DEBUG +private bool +wmatch(const byte *str, uint len, const byte *pstr, uint plen, + const string_match_params *psmp) +{ bool match = string_match(str, len, pstr, plen, psmp); + if ( gs_debug_c('e') ) + { dputs("[e]string_match(\""); + fwrite(str, 1, len, dstderr); + dputs("\", \""); + fwrite(pstr, 1, plen, dstderr); + dprintf1("\") = %s\n", (match ? "TRUE" : "false")); + } + return match; +} +#define string_match wmatch +#endif + +/* Search a string backward for a character. */ +/* (This substitutes for strrchr, which some systems don't provide.) */ +private char * +rchr(char *str, char ch, int len) +{ register char *p = str + len; + while ( p > str ) + if ( *--p == ch ) return p; + return 0; +} + +/* Pop a directory from the enumeration stack. */ +private bool +popdir(file_enum *pfen) +{ dirstack *d = pfen->dstack; + if ( d == 0 ) + return false; + pfen->dirp = d->entry; + pfen->dstack = d->next; + gs_free_object(pfen->memory, d, "gp_enumerate_files(popdir)"); + return true; +} + +/* Initialize an enumeration. */ +file_enum * +gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t *mem) +{ file_enum *pfen; + char *p; + char *work; + + /* Reject attempts to enumerate paths longer than the */ + /* system-dependent limit. */ + if ( patlen > MAXPATHLEN ) + return 0; + + /* Reject attempts to enumerate with a pattern containing zeroes. */ + { const char *p1; + for (p1 = pat; p1 < pat + patlen; p1++) + if (*p1 == 0) return 0; + } + /* >>> Should crunch strings of repeated "/"'s in pat to a single "/" + * >>> to match stupid unix filesystem "conventions" */ + + pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, + "gp_enumerate_files"); + if (pfen == 0) + return 0; + + /* pattern and work could be allocated as strings, */ + /* but it's simpler for GC and freeing to allocate them as bytes. */ + + pfen->pattern = + (char *)gs_alloc_bytes(mem, patlen + 1, + "gp_enumerate_files(pattern)"); + if (pfen->pattern == 0) + return 0; + memcpy(pfen->pattern, pat, patlen); + pfen->pattern[patlen] = 0; + + work = (char *)gs_alloc_bytes(mem, MAXPATHLEN+1, + "gp_enumerate_files(work)"); + if (work == 0) + return 0; + pfen->work = work; + + p = work; + memcpy(p, pat, patlen); + p += patlen; + *p = 0; + + /* Remove directory specifications beyond the first wild card. */ + /* Some systems don't have strpbrk, so we code it open. */ + p = pfen->work; + while ( !(*p == '*' || *p == '?' || *p == 0) ) p++; + while ( !(*p == '/' || *p == 0) ) p++; + if ( *p == '/' ) + *p = 0; + /* Substring for first wildcard match */ + pfen->pathead = p - work; + + /* Select the next higher directory-level. */ + p = rchr(work, '/', p - work); + if (!p) + { /* No directory specification */ + work[0] = 0; + pfen->worklen = 0; + } + else + { if (p == work) + { /* Root directory -- don't turn "/" into "" */ + p++; + } + *p = 0; + pfen->worklen = p - work; + } + + pfen->memory = mem; + pfen->dstack = 0; + pfen->first_time = true; + pfen->patlen = patlen; + return pfen; +} + +/* Enumerate the next file. */ +uint +gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen) +{ dir_entry *de; + char *work = pfen->work; + int worklen = pfen->worklen; + char *pattern = pfen->pattern; + int pathead = pfen->pathead; + int len; + struct stat stbuf; + + if ( pfen->first_time ) + { pfen->dirp = ((worklen == 0) ? opendir(".") : opendir(work)); + if_debug1('e', "[e]file_enum:First-Open '%s'\n", work); + pfen->first_time = false; + if (pfen->dirp == 0) /* first opendir failed */ + { gp_enumerate_files_close(pfen); + return ~(uint)0; + } + } + + top: de = readdir(pfen->dirp); + if (de == 0) + { /* No more entries in this directory */ + char *p; + + if_debug0('e', "[e]file_enum:Closedir\n"); + closedir(pfen->dirp); + /* Back working directory and matching pattern up one level */ + p = rchr(work,'/', worklen); + if (p != 0) + { if (p == work) p++; + *p = 0; + worklen = p - work; + } + else + worklen = 0; + p = rchr(pattern,'/', pathead); + if (p != 0) + pathead = p - pattern; + else + pathead = 0; + + if (popdir(pfen)) + { /* Back up the directory tree. */ + if_debug1('e', "[e]file_enum:Dir popped '%s'\n", work); + goto top; + } + else + { if_debug0('e', "[e]file_enum:Dirstack empty\n"); + gp_enumerate_files_close(pfen); + return ~(uint)0; + } + } + + /* Skip . and .. */ + len = strlen(de->d_name); + if (len <= 2 && (!strcmp(de->d_name,".") || !strcmp(de->d_name,"..") )) + goto top; + if (len + worklen + 1 > MAXPATHLEN) + /* Should be an error, I suppose */ + goto top; + if (worklen == 0) + { /* "Current" directory (evil un*x kludge) */ + memcpy(work, de->d_name, len + 1); + } + else if (worklen == 1 && work[0] == '/') + { /* Root directory */ + memcpy(work + 1, de->d_name, len + 1); + len = len + 1; + } + else + { work[worklen] = '/'; + memcpy(work + worklen + 1, de->d_name, len + 1); + len = worklen + 1 + len; + } + + /* Test for a match at this directory level */ + if (!string_match((byte *)work, len, (byte *)pattern, pathead, NULL)) + goto top; + + /* Perhaps descend into subdirectories */ + if (pathead < pfen->patlen) + { DIR *dp; + + if (((stat(work,&stbuf) >= 0) + ? !stat_is_dir(stbuf) + /* Couldn't stat it. + * Well, perhaps it's a directory and + * we'll be able to list it anyway. + * If it isn't or we can't, no harm done. */ + : 0)) + goto top; + + if (pfen->patlen == pathead + 1) + { /* Listing "foo/?/" -- return this entry */ + /* if it's a directory. */ + if (!stat_is_dir (stbuf)) + { /* Do directoryp test the hard way */ + dp = opendir(work); + if (!dp) goto top; + closedir(dp); + } + work[len++] = '/'; + goto winner; + } + + /* >>> Should optimise the case in which the next level */ + /* >>> of directory has no wildcards. */ + dp = opendir(work); +#ifdef DEBUG + { char save_end = pattern[pathead]; + pattern[pathead] = 0; + if_debug2('e', "[e]file_enum:fname='%s', p='%s'\n", + work, pattern); + pattern[pathead] = save_end; + } +#endif /* DEBUG */ + if (!dp) + /* Can't list this one */ + goto top; + else + { /* Advance to the next directory-delimiter */ + /* in pattern */ + char *p; + dirstack *d; + for (p = pattern + pathead + 1; ; p++) + { if (*p == 0) + { /* No more subdirectories to match */ + pathead = pfen->patlen; + break; + } + else if (*p == '/') + { pathead = p - pattern; + break; + } + } + + /* Push a directory onto the enumeration stack. */ + d = gs_alloc_struct(pfen->memory, dirstack, + &st_dirstack, + "gp_enumerate_files(pushdir)"); + if ( d != 0 ) + { + d->next = pfen->dstack; + d->entry = pfen->dirp; + pfen->dstack = d; + } + else + DO_NOTHING; /* >>> e_VMerror!!! */ + + if_debug1('e', "[e]file_enum:Dir pushed '%s'\n", + work); + worklen = len; + pfen->dirp = dp; + goto top; + } + } + + winner: + /* We have a winner! */ + pfen->worklen = worklen; + pfen->pathead = pathead; + memcpy(ptr, work, len); + return len; +} + +/* Clean up the file enumeration. */ +void +gp_enumerate_files_close(file_enum *pfen) +{ gs_memory_t *mem = pfen->memory; + + if_debug0('e', "[e]file_enum:Cleanup\n"); + while (popdir(pfen)) /* clear directory stack */ + DO_NOTHING; + gs_free_object(mem, (byte *)pfen->work, + "gp_enumerate_close(work)"); + gs_free_object(mem, (byte *)pfen->pattern, + "gp_enumerate_files_close(pattern)"); + gs_free_object(mem, pfen, "gp_enumerate_files_close"); +} + +/* Test-cases: + (../?*r*?/?*.ps) {==} 100 string filenameforall + (../?*r*?/?*.ps*) {==} 100 string filenameforall + (../?*r*?/) {==} 100 string filenameforall + (/t*?/?*.ps) {==} 100 string filenameforall +*/ diff --git a/pstoraster/gp_unix.c b/pstoraster/gp_unix.c new file mode 100644 index 0000000000..d81553c725 --- /dev/null +++ b/pstoraster/gp_unix.c @@ -0,0 +1,174 @@ +/* Copyright (C) 1989, 1995, 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gp_unix.c */ +/* Unix-specific routines for Ghostscript */ +#include "string_.h" +#include "gx.h" +#include "gsexit.h" +#include "gp.h" +#include "time_.h" + +#if defined(SYSV) || defined(SVR4) || defined(CLK_TCK) +#include +#endif + +/* + * Because of inconsistent (and sometimes incorrect) header files, + * we must omit the argument list for popen. + */ +extern FILE *popen( /* P2(const char *, const char *) */ ); +extern int pclose(P1(FILE *)); +/* + * This is the only place in Ghostscript that calls 'exit'. Including + * is overkill, but that's where it's declared on ANSI systems. + * We don't have any way of detecting whether we have a standard library + * (some GNU compilers perversely define __STDC__ but don't provide + * an ANSI-compliant library), so we check __PROTOTYPES__ and + * hope for the best. We pick up getenv at the same time. + */ +#ifdef __PROTOTYPES__ +# include /* for exit and getenv */ +#else +extern void exit(P1(int)); +extern char *getenv(P1(const char *)); +#endif + +/* Do platform-dependent initialization. */ +void +gp_init(void) +{ +} + +/* Do platform-dependent cleanup. */ +void +gp_exit(int exit_status, int code) +{ +} + +/* Exit the program. */ +void +gp_do_exit(int exit_status) +{ exit(exit_status); +} + +/* ------ Miscellaneous ------ */ + +/* Get the string corresponding to an OS error number. */ +/* Unix systems support this so inconsistently that we don't attempt */ +/* to figure out whether it's available. */ +const char * +gp_strerror(int errnum) +{ return NULL; +} + +/* ------ Date and time ------ */ + +/* Read the current time (in seconds since Jan. 1, 1970) */ +/* and fraction (in nanoseconds). */ +void +gp_get_realtime(long *pdt) +{ struct timeval tp; + +#if gettimeofday_no_timezone /* older versions of SVR4 */ + { if ( gettimeofday(&tp) == -1 ) + { lprintf("Ghostscript: gettimeofday failed!\n"); + gs_exit(1); + } + } +#else /* All other systems */ + { struct timezone tzp; + if ( gettimeofday(&tp, &tzp) == -1 ) + { lprintf("Ghostscript: gettimeofday failed!\n"); + gs_exit(1); + } + } +#endif + + /* tp.tv_sec is #secs since Jan 1, 1970 */ + pdt[0] = tp.tv_sec; + + /* Some Unix systems (e.g., Interactive 3.2 r3.0) return garbage */ + /* in tp.tv_usec. Try to filter out the worst of it here. */ + pdt[1] = tp.tv_usec >= 0 && tp.tv_usec < 1000000 ? tp.tv_usec*1000 : 0; + +#ifdef DEBUG_CLOCK + printf("tp.tv_sec = %d tp.tv_usec = %d pdt[0] = %ld pdt[1] = %ld\n", + tp.tv_sec, tp.tv_usec, pdt[0], pdt[1]); +#endif +} + +/* Read the current user CPU time (in seconds) */ +/* and fraction (in nanoseconds). */ +void +gp_get_usertime(long *pdt) +{ +#if use_times_for_usertime + struct tms tms; + long ticks; + + static long ticks_per_sec; + if ( !ticks_per_sec ) /* not initialized yet */ + ticks_per_sec = CLK_TCK; + + times(&tms); + ticks = tms.tms_utime + tms.tms_stime + tms.tms_cutime + tms.tms_cstime; + pdt[0] = ticks / ticks_per_sec; + pdt[1] = (ticks % ticks_per_sec) * (1000000000 / ticks_per_sec); +#else + gp_get_realtime(pdt); /* Use an approximation on other hosts. */ +#endif +} + +/* ------ Screen management ------ */ + +/* Get the environment variable that specifies the display to use. */ +const char * +gp_getenv_display(void) +{ return getenv("DISPLAY"); +} + +/* ------ Printer accessing ------ */ + +/* Open a connection to a printer. A null file name means use the */ +/* standard printer connected to the machine, if any. */ +/* "|command" opens an output pipe. */ +/* Return NULL if the connection could not be opened. */ +FILE * +gp_open_printer(char *fname, int binary_mode) +{ return + (strlen(fname) == 0 ? + gp_open_scratch_file(gp_scratch_file_name_prefix, fname, "w") : + fname[0] == '|' ? + popen(fname + 1, "w") : + fopen(fname, "w")); +} + +/* Close the connection to the printer. */ +void +gp_close_printer(FILE *pfile, const char *fname) +{ if ( fname[0] == '|' ) + pclose(pfile); + else + fclose(pfile); +} diff --git a/pstoraster/gpcheck.h b/pstoraster/gpcheck.h new file mode 100644 index 0000000000..c9308931c4 --- /dev/null +++ b/pstoraster/gpcheck.h @@ -0,0 +1,58 @@ +/* Copyright (C) 1992, 1994 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gpcheck.h */ +/* Interrupt check interface */ + +/* + * On some platforms, the interpreter must check periodically for user- + * initiated actions. (Eventually, this may be extended to all platforms, + * to handle multi-tasking through the 'context' facility.) Routines that + * run for a long time must periodically call gp_check_interrupts(), and + * if it returns true, must clean up whatever they are doing and return an + * e_interrupted (or gs_error_interrupted) exceptional condition. + * The return_if_interrupt macro provides a convenient way to do this. + * + * On platforms that require an interrupt check, the makefile defines + * a symbol CHECK_INTERRUPTS. Currently this is only the Microsoft + * Windows platform. + */ + +#ifdef CHECK_INTERRUPTS +int gp_check_interrupts(P0()); +int gs_return_check_interrupt(P1(int code)); +# define process_interrupts() discard(gp_check_interrupts()) +# define return_if_interrupt()\ + { int icode_ = gp_check_interrupts();\ + if ( icode_ )\ + return gs_note_error((icode_ > 0 ? gs_error_interrupt : icode_));\ + } +# define return_check_interrupt(code)\ + return gs_return_check_interrupt(code) +#else +# define gp_check_interrupts() 0 +# define process_interrupts() DO_NOTHING +# define return_if_interrupt() DO_NOTHING +# define return_check_interrupt(code)\ + return (code) +#endif diff --git a/pstoraster/gs_btokn.ps b/pstoraster/gs_btokn.ps new file mode 100644 index 0000000000..1a81a6c868 --- /dev/null +++ b/pstoraster/gs_btokn.ps @@ -0,0 +1,287 @@ +% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Initialization file for binary tokens. +% When this is run, systemdict is still writable, +% but everything defined here goes into level2dict. + +% Define whether or not to allow writing dictionaries. +/WRITEDICTS true def + +languagelevel 1 .setlanguagelevel +level2dict begin + +% Initialization for the system name table. + +mark +% 0 + /abs /add /aload /anchorsearch /and + /arc /arcn /arct /arcto /array + /ashow /astore /awidthshow /begin /bind + /bitshift /ceiling /charpath /clear /cleartomark +% 20 + /clip /clippath /closepath /concat /concatmatrix + /copy /count /counttomark /currentcmykcolor /currentdash + /currentdict /currentfile /currentfont /currentgray /currentgstate + /currenthsbcolor /currentlinecap /currentlinejoin /currentlinewidth /currentmatrix +% 40 + /currentpoint /currentrgbcolor /currentshared /curveto /cvi + /cvlit /cvn /cvr /cvrs /cvs + /cvx /def /defineusername /dict /div + /dtransform /dup /end /eoclip /eofill +% 60 + /eoviewclip /eq /exch /exec /exit + /file /fill /findfont /flattenpath /floor + /flush /flushfile /for /forall /ge + /get /getinterval /grestore /gsave /gstate +% 80 + /gt /identmatrix /idiv /idtransform /if + /ifelse /image /imagemask /index /ineofill + /infill /initviewclip /inueofill /inufill /invertmatrix + /itransform /known /le /length /lineto +% 100 + /load /loop /lt /makefont /matrix + /maxlength /mod /moveto /mul /ne + /neg /newpath /not /null /or + /pathbbox /pathforall /pop /print /printobject +% 120 + /put /putinterval /rcurveto /read /readhexstring + /readline /readstring /rectclip /rectfill /rectstroke + /rectviewclip /repeat /restore /rlineto /rmoveto + /roll /rotate /round /save /scale +% 140 + /scalefont /search /selectfont /setbbox /setcachedevice + /setcachedevice2 /setcharwidth /setcmykcolor /setdash /setfont + /setgray /setgstate /sethsbcolor /setlinecap /setlinejoin + /setlinewidth /setmatrix /setrgbcolor /setshared /shareddict +% 160 + /show /showpage /stop /stopped /store + /string /stringwidth /stroke /strokepath /sub + /systemdict /token /transform /translate /truncate + /type /uappend /ucache /ueofill /ufill +% 180 + /undef /upath /userdict /ustroke /viewclip + /viewclippath /where /widthshow /write /writehexstring + /writeobject /writestring /wtranslation /xor /xshow + /xyshow /yshow /FontDirectory /SharedFontDirectory /Courier +% 200 + /Courier-Bold /Courier-BoldOblique /Courier-Oblique /Helvetica /Helvetica-Bold + /Helvetica-BoldOblique /Helvetica-Oblique /Symbol /Times-Bold /Times-BoldItalic + /Times-Italic /Times-Roman /execuserobject /currentcolor /currentcolorspace + /currentglobal /execform /filter /findresource /globaldict +% 220 + /makepattern /setcolor /setcolorspace /setglobal /setpagedevice + /setpattern +% pad to 256 + counttomark 256 exch sub { 0 } repeat +% 256 + /= /== /ISOLatin1Encoding /StandardEncoding +% 260 + ([) cvn (]) cvn /atan /banddevice /bytesavailable + /cachestatus /closefile /colorimage /condition /copypage + /cos /countdictstack /countexecstack /cshow /currentblackgeneration + /currentcacheparams /currentcolorscreen /currentcolortransfer /currentcontext /currentflat +% 280 + /currenthalftone /currenthalftonephase /currentmiterlimit /currentobjectformat /currentpacking + /currentscreen /currentstrokeadjust /currenttransfer /currentundercolorremoval /defaultmatrix + /definefont /deletefile /detach /deviceinfo /dictstack + /echo /erasepage /errordict /execstack /executeonly +% 300 + /exp /false /filenameforall /fileposition /fork + /framedevice /grestoreall /handleerror /initclip /initgraphics + /initmatrix /instroke /inustroke /join /kshow + /ln /lock /log /mark /monitor +% 320 + /noaccess /notify /nulldevice /packedarray /quit + /rand /rcheck /readonly /realtime /renamefile + /renderbands /resetfile /reversepath /rootfont /rrand + /run /scheck /setblackgeneration /setcachelimit /setcacheparams +% 340 + /setcolorscreen /setcolortransfer /setfileposition /setflat /sethalftone + /sethalftonephase /setmiterlimit /setobjectformat /setpacking /setscreen + /setstrokeadjust /settransfer /setucacheparams /setundercolorremoval /sin + /sqrt /srand /stack /status /statusdict +% 360 + /true /ucachestatus /undefinefont /usertime /ustrokepath + /version /vmreclaim /vmstatus /wait /wcheck + /xcheck /yield /defineuserobject /undefineuserobject /UserObjects + /cleardictstack +% 376 + /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 + /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 +% 428 + /setvmthreshold (<<) cvn + (>>) cvn /currentcolorrendering /currentdevparams /currentoverprint /currentpagedevice + /currentsystemparams /currentuserparams /defineresource /findencoding /gcheck +% 440 + /glyphshow /languagelevel /product /pstack /resourceforall + /resourcestatus /revision /serialnumber /setcolorrendering /setdevparams + /setoverprint /setsystemparams /setuserparams /startjob /undefineresource + /GlobalFontDirectory /ASCII85Decode /ASCII85Encode /ASCIIHexDecode /ASCIIHexEncode +% 460 + /CCITTFaxDecode /CCITTFaxEncode /DCTDecode /DCTEncode /LZWDecode + /LZWEncode /NullEncode /RunLengthDecode /RunLengthEncode /SubFileDecode + /CIEBasedA /CIEBasedABC /DeviceCMYK /DeviceGray /DeviceRGB + /Indexed /Pattern /Separation +% 478 -- end +.packtomark + +% Install the system and user name tables. +% The user name table is read-only for ordinary programs, +% since it doesn't obey save/restore and must be managed specially. + +dup /SystemNames exch def +100 array readonly dup /UserNames exch def +.installnames + +% Define printobject and writeobject. +% These are mostly implemented in PostScript, so that we don't have to +% worry about interrupts or callbacks when writing to the output file. + +% Define procedures for accumulating the space required to represent +% an object in binary form. +/cntdict mark % <#refs> <#chars> -proc- <#refs> <#chars> + /integertype /pop load + /realtype 1 index + /marktype 1 index + /nulltype 1 index + /booleantype 1 index + /nametype { length add } bind + /stringtype 1 index + /arraytype null + WRITEDICTS { /dicttype null } if +.dicttomark def +cntdict /arraytype + { dup dup length 5 -1 roll add 4 2 roll + { dup type //cntdict exch get exec } forall + } bind put +WRITEDICTS + { cntdict /dicttype + { dup dup length 2 mul 5 -1 roll add 4 2 roll + { 4 1 roll dup type //cntdict exch get exec + 3 -1 roll dup type //cntdict exch get exec + } forall + } bind put + } if + +/w2dict mark + /nametype { 2 copy .writecvs pop } bind + /stringtype 1 index +.dicttomark def + +/.writeobjects % .writeobjects - + { + mark exch + + % Count the space required for refs and strings. + dup length 0 3 -1 roll + % Stack: -mark- <#refs> <#chars> + + dup 4 1 roll + { dup type //cntdict exch get exec + } forall + + % Write the header. + % Stack: -mark- ... <#refs> <#chars> + counttomark 3 add -2 roll 4 1 roll + % Stack: -mark- ... <#refs> <#chars> + dup counttomark 1 sub index length + 4 index 3 bitshift 4 index add + (xxxxxxxx) .bosheader writestring + + % Write the objects per se. + 3 1 roll pop + counttomark 1 sub index length 3 bitshift exch + 3 bitshift + % Stack: -mark- ... + + counttomark 4 sub + { counttomark -1 roll dup 6 1 roll + dup type /dicttype eq % can't be first object + { { 5 1 roll (xxxxxxxx) .bosobject + 3 index exch writestring + 4 -1 roll (xxxxxxxx) .bosobject + 3 index exch writestring + } forall + } + { { (xxxxxxxx) .bosobject + dup 1 6 index put + 3 index exch writestring + 4 -1 roll pop 0 4 1 roll % clear tag + } forall + } + ifelse + } + repeat + + % Write the strings and names. + pop pop exch pop + % Stack: -mark- ... + + counttomark 1 sub + { counttomark -1 roll + { % The counting pass ensured that the keys and values + % of any dictionary must be writable objects. + % Hence, we are processing a dictionary iff + % the next-to-top stack element is not a file. + 1 index type /filetype ne + { exch 2 index exch dup type //w2dict exch .knownget + { exec } { pop } ifelse pop + } + if + dup type //w2dict exch .knownget { exec } { pop } ifelse + } forall + } + repeat + + % Clean up. + % Stack: -mark- + + pop pop + + } odef +currentdict /cntdict .undef +currentdict /w2dict .undef + +/printobject { (%stderr) (w) file 3 1 roll writeobject } odef +/writeobject { exch 1 array astore .writeobjects } odef + +% Implement binary error message output. + /.printerror + { $error /binary get .languagelevel 2 eq and + { currentobjectformat 0 ne + { [ /Error $error /errorname get $error /command get false + ] 250 printobject + } + //.printerror + ifelse + } + //.printerror + ifelse + } bind def + +% End of level2dict + +end +.setlanguagelevel diff --git a/pstoraster/gs_ccfnt.ps b/pstoraster/gs_ccfnt.ps new file mode 100644 index 0000000000..faec930f9c --- /dev/null +++ b/pstoraster/gs_ccfnt.ps @@ -0,0 +1,98 @@ +% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Find and register all the precompiled font operators in systemdict. + +/registerfont % registerfont + { DEBUG { (Registering ) print 1 index = } if + dup begin + Encoding type /nametype eq + { Encoding .findencoding /Encoding exch def + } + if + dup /PrefEnc known + { PrefEnc type /nametype eq + { PrefEnc .findencoding /PrefEnc exch def + } + if + } + if + dup /FDepVector known + { /FDepVector [ FDepVector + { FontDirectory 1 index .knownget + { exch pop } + { ccfonts 1 index .knownget + { registerfont + } + { Fontmap 1 index known + { findfont } + { pop NullFont } + ifelse + } + ifelse + } + ifelse + } + forall ] readonly def + } + if + end + % Use the value of definefont appropriate at run-time, not bind-time + /definefont load exec + } bind odef +% Bind recursive call (bind descends into oparrays: feature!) +/registerfont dup load bind def + +/.loadinitialfonts { + //.loadinitialfonts exec + /ccfonts mark + 0 1 null .getccfont 1 sub { .getccfont dup /FontName get exch } for + .dicttomark def + ccfonts + { FontDirectory 2 index known { pop pop } { registerfont pop } ifelse } + forall + currentdict /ccfonts .undef +} bind def + +currentdict /registerfont .undef + + +% If we're in a Level 2 system but running in Level 1 mode, +% register the fonts explicitly as resources. +% This is a bit of a hack, but doing better is too much work. + +/level2dict where + { pop /findresource where + { % Level 2 system, Level 2 mode + pop + } + { % Level 2 system, Level 1 mode + /Font /Category level2dict /findresource get exec begin + FontDirectory + { dup .gcheck { Instances } { LocalInstances } ifelse + 3 1 roll [exch 0 -1] .growput + } + forall end + } + ifelse + } +if diff --git a/pstoraster/gs_cidfn.ps b/pstoraster/gs_cidfn.ps new file mode 100644 index 0000000000..395986462c --- /dev/null +++ b/pstoraster/gs_cidfn.ps @@ -0,0 +1,127 @@ +% Copyright (C) 1995 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% ProcSet for implementing CID-keyed fonts. +% When this is run, systemdict is still writable. + +%**************** This file is not ready for use: +% - It doesn't include the actual character mapper (BuildGlyph). +% - It loads the entire font into RAM. +% - It has never been tested on a real font. + +/.setlanguagelevel where { pop 2 .setlanguagelevel } if +.currentglobal true .setglobal + +/GS_CIDInit_ProcSet 30 dict dup begin + +% ---------------- CIDFont operators ---------------- % + +/StartData % <(Binary)|(Hex)> + % StartData - + { 2 index begin % CID font dict + 20 dict begin % temporary dict + /datalength exch def + (Hex) eq /hex exch def + /cidfont exch def + /startdata currentfile fileposition def + + % Read the character data into an array of strings. + % There's no particular reason to prefer long strings over short, + % so we just create a separate string for each character. + + /charstrings CIDCount array def + /fontindices CIDCount FDBytes 1 eq { string } { array } ifelse def + 0 1 CIDCount 1 sub + { /cid exch def + currentfile FDBytes GDBytes add cid mul startdata add setfileposition + fontindices cid FDBytes .readint put + charstrings cid + /pos GDBytes .readint def + FDBytes .readint pop % skip FD of next entry + GDBytes .readint pos sub + dup 0 eq + { pop null } + { currentfile pos setfileposition string readstring pop } + ifelse put + } + for + + % Process each font in the FDArray. + % For Type 3 fonts, just do a definefont with an empty Encoding. + % For Type 1 fonts, read the Subrs (don't bother to check for + % duplicates), and set CharStrings to the character data array. + % We don't support embedded Type 0 fonts, but it isn't clear + % whether they're allowed anyway. + + cidfont /FDepVector [ FDArray + { dup /FontType get 1 eq + { dup /CharStrings charstrings put + /Private get + dup /SubrCount known + { begin /Subrs [ % Private + 0 1 SubrCount 1 sub + { SDBytes mul SubrMapOffset add startdata add + currentfile exch setfileposition + /pos SDBytes .readint def + SDBytes .readint pos sub + currentfile pos setfileposition string readstring pop + } + ] readonly def end % Private + } + if pop + } + if + dup /Encoding [] put + dup /FontName get exch definefont + } + forall ] readonly def + + % Install the rest of the data in the font. + + cidfont /CharStrings charstrings readonly put + cidfont /FontIndices fontindices readonly put + FontName cidfont /CIDFont defineresource pop + + % Wrap up. + + end % temporary dict + end % CID font dict + end % resource dict + } bind def + +/.readint % .readint + { 0 exch { 8 bitshift currentfile read pop add } repeat + } bind def + +% ---------------- Resource category definition ---------------- % + +end readonly def + +/defineresource where + { pop + /CIDFont /Generic /Category findresource dup length dict .copydict + /Category defineresource pop + /CIDInit GS_CIDInit_ProcSet /ProcSet defineresource pop + } +if + +.setglobal diff --git a/pstoraster/gs_cmap.ps b/pstoraster/gs_cmap.ps new file mode 100644 index 0000000000..8b699811ec --- /dev/null +++ b/pstoraster/gs_cmap.ps @@ -0,0 +1,235 @@ +% Copyright (C) 1995 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% ProcSet for implementing CMap resource. +% When this is run, systemdict is still writable. + +%**************** This file is not ready for use: +% - Rearranged fonts are not implemented. +% - It has never been tested on a real font. + +/.setlanguagelevel where { pop 2 .setlanguagelevel } if +.currentglobal true .setglobal + +/GS_CMapInit_ProcSet 30 dict dup begin + +% ---------------- CMap operators ---------------- % + +% We create the following structures for character code mapping. +% Map - a multi-level array indexed by the successive bytes of +% the character code. All of the arrays are read-only. +% NotdefMap - the same. + +% ------ Font-level operators ------ % + +% composefont doesn't appear in CMap files -- it's documented in +% the "PostScript Language Reference Manual Supplement". +/composefont % composefont + { exch dup /dicttype ne { /CMap findresource } if + 10 dict + dup /FontType 0 put + dup /FMapType 9 put + dup /CMap 5 -1 roll put + dup /Encoding [ 0 1 6 index length 1 sub { } for ] put + dup /FDepVector 4 -1 roll put + /Font defineresource + } bind def + +/begincmap % - begincmap - + { /Map 256 array def + /NotdefMap 256 array def + } bind def +/endcmap % - endcmap - + { /Map Map .endmap def + /NotdefMap NotdefMap .endmap def + } bind def + +/begincodespacerange % begincodespacerange - + { pop mark + } bind def +/endcodespacerange % ... endcodespacerange - + { counttomark 2 idiv + { 2 copy Map .addcodespacerange NotdefMap .addcodespacerange + } repeat pop + } bind def + +/.addcodespacerange % .addcodespacerange - + { 2 index length 1 eq + { 2 { 3 -1 roll 0 get } repeat 1 exch + { 2 copy 0 put pop } for pop + } + { 2 index 0 get 1 3 index 0 get + 6 -2 roll + 2 { 1 1 index length 1 sub getinterval 6 1 roll } repeat + % Stack: lo hi map lo0 1 hi0 + { 2 copy get null eq { 2 copy 256 array put } if + 4 copy get .addcodespacerange pop + } + for pop pop pop + } + ifelse + } bind def +/.endmap % .endmap + { dup type /arraytype eq { dup { .endmap exch } forall astore readonly } if + } bind def + +/usecmap % usecmap - + { /CMap findresource + dup length dict .copydict + currentdict end exch .copydict begin + } bind def + +% ------ Rearranged font operators ------ % + +/beginrearrangedfont % beginrearrangedfont - + { (NOT IMPLEMENTED YET.\n) print flush + } bind def +/endrearrangedfont % - endrearrangedfont - + { (NOT IMPLEMENTED YET.\n) print flush + } bind def + +/usefont % usefont - + { (NOT IMPLEMENTED YET.\n) print flush + } bind def + +/beginusematrix % beginusematrix - + { (NOT IMPLEMENTED YET.\n) print flush + } bind def +/endusematrix % endusematrix - + { (NOT IMPLEMENTED YET.\n) print flush + } bind def + +% ------ Character name/code selector operators ------ % + +/beginbfchar % beginbfchar - + { pop mark + } bind def +/endbfchar % ... endbfchar + { Map .endmapchar /Map exch store pop + } bind def + +/beginbfrange % beginbfrange - + { pop mark + } bind def +/endbfrange % ... + % endbfrange - + { Map counttomark 3 idiv { .addbfrange } repeat /Map exch store pop + } bind def + +/.addbfrange % + % .addbfrange + { 1 index type /stringtype eq + { { dup length string copy dup dup length 1 sub 2 copy get 1 add put } + exch .addmaprange + } + { 2 dict begin exch /codes 1 index def 0 get exch + { codes dup length 1 sub 1 exch getinterval /codes 1 index def + dup length 0 gt { 0 get } if + } + exch .addmaprange end + } + ifelse exch pop + } bind def + +% ------ CID selector operators ------ % + +/begincidchar % begincidchar - + { pop mark + } bind def +/endcidchar % ... endcidchar - + { Map .endmapchar /Map exch store pop + } bind def + +/begincidrange % begincidrange - + { pop mark + } bind def +/endcidrange % ... endcidrange - + { Map counttomark 3 idiv { { 1 add } exch .addmaprange exch pop } repeat + /Map exch store pop + } bind def + +/.endmapchar % ... .endmapchar - + { counttomark 2 idiv + { 2 index 3 1 roll { } exch .addmaprange exch pop + } repeat exch pop + } bind def + +/.addmaprange % + % .addcidrange + { % We may be updating a (partly) read-only map from another CMap. + % If so, implement copy-on-write. + dup wcheck not { dup length array copy } if + 4 index length 1 eq + { 2 { 5 -1 roll 0 get } repeat 1 exch + { % Stack: value proc map code + 2 copy 5 index put pop + 3 -1 roll 2 index exec 3 1 roll + } for + } + { 4 index 0 get 1 5 index 0 get + 8 -2 roll + 2 { 1 1 index length 1 sub getinterval 8 1 roll } repeat + % Stack: lo hi next proc map lo0 1 hi0 + { 6 copy get .addmaprange + % Stack: lo hi oldnext proc map i next submap + exch 6 1 roll 5 -1 roll pop + % Stack: lo hi next proc map i submap + 3 copy put pop pop + } + for 5 -2 roll pop pop + } + ifelse exch pop + } bind def + +% ------ notdef operators ------ % + +/beginnotdefchar % beginnotdefchar - + { pop mark + } bind def +/endnotdefchar % ... endnotdefchar - + { counttomark 2 idiv { 1 index exch .addnotdefrange } repeat pop + } bind def + +/beginnotdefrange % beginnotdefrange - + { pop mark + } bind def +/endnotdefrange % ... endnotdefrange - + { counttomark 3 idiv { .addnotdefrange } repeat pop + } bind def + +/.addnotdefrange % .addnotdefrange - + { { } NotdefMap .addmaprange /NotdefMap exch store pop + } bind def + +% ---------------- Resource category definition ---------------- % + +end readonly def + +/defineresource where + { pop + /CMap /Generic /Category findresource dup length dict .copydict + /Category defineresource pop + /CMapInit GS_CMapInit_ProcSet /ProcSet defineresource pop + } +if + +.setglobal diff --git a/pstoraster/gs_cmdl.ps b/pstoraster/gs_cmdl.ps new file mode 100644 index 0000000000..ad6dfbcc05 --- /dev/null +++ b/pstoraster/gs_cmdl.ps @@ -0,0 +1,186 @@ +% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Parse and execute the command line. +% C code handles the following switches: -h/-? -I -M -v + +/cmddict 50 dict def +cmddict begin + +% ---------------- Utility procedures ---------------- % + +% Get the next argument from the parsed argument list. +/nextarg % - nextarg true + % - nextarg false + { argv length 0 eq + { false } + { argv dup 0 get exch dup length 1 sub 1 exch getinterval /argv exch def } + ifelse + } bind def + +% Run a file, under job control if implemented. +/runjob % runjob - + { end % cmddict + /startjob where { pop false () startjob pop } + run + //cmddict begin + } bind def +/runfilejob % runfilejob - + { findlibfile { exch pop } { (r) file } runjob + } bind def + +% Expand arguments. Free variables: expand@. +/expandarg % expandarg + { dup () eq + { pop + } + { dup dup (--) eq exch (-+) eq or + { pop /expand@ false def + } + { expand@ { (@) anchorsearch } { false } ifelse + { pop findlibfile + { exch pop } + { (r) file } % let the error happen + expandargfile + } + if + } + ifelse + } + } bind def +/expandargfile % expandargfile + { [ exch cvlit + { token not { exit } if + dup type /stringtype ne { =string cvs dup length string copy } if + expandarg + } + /exec cvx + ] cvx loop + } bind def + +% ---------------- Recognized switches ---------------- % + +% Switches with arguments are defined as ; +% switches without arguments are defined as -. + +% Switches without arguments +/-- + { nextarg not + { (-- and -+ require a file name.\n) print flush } + { //systemdict /ARGUMENTS argv put /argv [] def runjob } + ifelse + } bind def +/-+ /-- load def +/-@ /-- load def +/-A { (@) Z } bind def +/-c + { { argv length 0 eq { exit } if + argv 0 get (-) anchorsearch { pop pop exit } if + pop nextarg token + { exch pop % Probably should check for empty. + end exec //cmddict begin + } + if + } + loop + } bind def +/-e { (#) Z } bind def +/-E /-e load def +/-f { } def +/-q { //systemdict /QUIET true put } bind def + +% Switches with arguments +/d + { (=) search not { (#) search not { () exch dup } if } if + exch pop cvn dup where + { pop (Redefining ) print print ( is not allowed.\n) print flush pop } + { exch token + { exch pop } % Probably should check for empty. + { true } + ifelse + //systemdict 3 1 roll put + } + ifelse + } bind def +/D /d load def +/f { dup length 0 ne { runfilejob } if } bind def +/g + { (x) search { cvi pop exch cvi } { cvi dup } ifelse + //systemdict begin /DEVICEHEIGHT exch def /DEVICEWIDTH exch def end + } bind def +/r + { (x) search { cvr pop exch cvr } { cvr dup } ifelse + //systemdict begin /DEVICEYRESOLUTION exch def /DEVICEXRESOLUTION exch def end + } bind def +/s + { (=) search not { (#) search not { () exch dup } if } if + exch pop cvn dup where { pop dup load } { () } ifelse + type /stringtype ne + { (Redefining ) print print ( is not allowed.\n) print flush pop } + { exch //systemdict 3 1 roll put } + ifelse + } bind def +/S /s load def +/Z { true .setdebug } bind def + +% ---------------- Main program ---------------- % + +% We process the command line in two passes. In the first pass, +% we read and expand any @-files as necessary. The second pass +% does the real work. + +/cmdstart + { //cmddict begin + /expand@ true def + [ + % Process the GS_OPTIONS environment variable. + (GS_OPTIONS) getenv { 0 () /SubFileDecode filter expandargfile } if + % Process the actual command line. + .getargv { expandarg } forall + ] readonly /argv exch def + % Now interpret the commands. + { nextarg not { exit } if + dup 0 get (-) 0 get eq + { dup length 1 eq + { pop (%stdin) (r) file runjob + } + { dup length 2 gt + { dup dup length 2 sub 2 exch getinterval exch 1 1 getinterval } + if currentdict .knownget + { exec + } + { (Ignoring unknown switch ) print + dup length 1 eq { (-) print print } if print + (\n) print flush + } + ifelse + } + ifelse + } + { runfilejob + } + ifelse + } + loop end + } bind def + +end % cmddict diff --git a/pstoraster/gs_dbt_e.ps b/pstoraster/gs_dbt_e.ps new file mode 100644 index 0000000000..70c1537623 --- /dev/null +++ b/pstoraster/gs_dbt_e.ps @@ -0,0 +1,65 @@ +% Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Define the Dingbats encoding vector. +/currentglobal where + { pop currentglobal { setglobal } true setglobal } + { { } } +ifelse +/DingbatsEncoding +% \000 + StandardEncoding 0 32 getinterval aload pop % /.notdef +% \040 + /space /a1 /a2 /a202 /a3 /a4 /a5 /a119 + /a118 /a117 /a11 /a12 /a13 /a14 /a15 /a16 + /a105 /a17 /a18 /a19 /a20 /a21 /a22 /a23 + /a24 /a25 /a26 /a27 /a28 /a6 /a7 /a8 +% \100 + /a9 /a10 /a29 /a30 /a31 /a32 /a33 /a34 + /a35 /a36 /a37 /a38 /a39 /a40 /a41 /a42 + /a43 /a44 /a45 /a46 /a47 /a48 /a49 /a50 + /a51 /a52 /a53 /a54 /a55 /a56 /a57 /a58 +% \140 + /a59 /a60 /a61 /a62 /a63 /a64 /a65 /a66 + /a67 /a68 /a69 /a70 /a71 /a72 /a73 /a74 + /a203 /a75 /a204 /a76 /a77 /a78 /a79 /a81 + /a82 /a83 /a84 /a97 /a98 /a99 /a100 /.notdef +% \200 + StandardEncoding 0 32 getinterval aload pop % /.notdef +% \240 + /.notdef /a101 /a102 /a103 /a104 /a106 /a107 /a108 + /a112 /a111 /a110 /a109 /a120 /a121 /a122 /a123 + /a124 /a125 /a126 /a127 /a128 /a129 /a130 /a131 + /a132 /a133 /a134 /a135 /a136 /a137 /a138 /a139 +% \300 + /a140 /a141 /a142 /a143 /a144 /a145 /a146 /a147 + /a148 /a149 /a150 /a151 /a152 /a153 /a154 /a155 + /a156 /a157 /a158 /a159 /a160 /a161 /a163 /a164 + /a196 /a165 /a192 /a166 /a167 /a168 /a169 /a170 +% \340 + /a171 /a172 /a173 /a162 /a174 /a175 /a176 /a177 + /a178 /a179 /a193 /a180 /a199 /a181 /a200 /a182 + /.notdef /a201 /a183 /a184 /a197 /a185 /a194 /a198 + /a186 /a195 /a187 /a188 /a189 /a190 /a191 /.notdef +256 packedarray .defineencoding +3 DingbatsEncoding .registerencoding +exec diff --git a/pstoraster/gs_diskf.ps b/pstoraster/gs_diskf.ps new file mode 100644 index 0000000000..4d55fd6f13 --- /dev/null +++ b/pstoraster/gs_diskf.ps @@ -0,0 +1,230 @@ +% Copyright (C) 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Support for converting Type 1 fonts without eexec encryption to +% Type 4 fonts that load individual character outlines on demand. + +% If DISKFONTS is true, we load individual CharStrings as they are needed. +% (This is intended primarily for machines with very small memories.) +% Initially, the character definition is the file position of the definition; +% this gets replaced with the actual CharString. +% Note that if we are loading characters lazily, CharStrings is writable. + +% _Cstring must be long enough to hold the longest CharString for +% a character defined using seac. This is lenIV + 4 * 5 (for the operands +% of sbw, assuming div is not used) + 2 (for sbw) + 3 * 5 (for the operands +% of seac other than the character codes) + 2 * 2 (for the character codes) +% + 2 (for seac), i.e., lenIV + 43. + +/_Cstring 60 string def + +% When we initially load the font, we call +% cskip_C +% to skip over each character definition and return the file position instead. +% This substitutes for the procedure +% string currentfile exch read[hex]string pop +% [encrypt] +% What we actually store in the CharString is fileposition * 1000 + length, +% negated if the string is stored in binary form. + +/cskip_C + { exch dup 1000 ge 3 index type /nametype ne or + { % This is a Subrs string, or the string is so long we can't represent + % its length. Load it now. + exch exec + } + { % Record the position and length, and skip the string. + dup currentfile fileposition 1000 mul add + 2 index 3 get /readstring cvx eq { neg } if + 3 1 roll + dup _Cstring length idiv + { currentfile _Cstring 3 index 3 get exec pop pop + } repeat + _Cstring length mod _Cstring exch 0 exch getinterval + currentfile exch 3 -1 roll 3 get exec pop pop + } + ifelse + } bind def + +% Load a CharString from the file. The font is the top entry +% on the dictionary stack. +/load_C % load_C - + { dup abs 1000 idiv FontFile exch setfileposition + CharStrings 3 1 roll + .currentglobal CharStrings .gcheck .setglobal exch + dup 0 lt + { neg 1000 mod string FontFile exch readstring } + { 1000 mod string FontFile exch readhexstring } + ifelse pop + exch .setglobal +% If the CharStrings aren't encrypted on the file, encrypt now. + Private /-| get 0 get + dup type /nametype ne + { dup length 5 sub 5 exch getinterval exec } + { pop } + ifelse dup 4 1 roll put +% If the character is defined with seac, load its components now. + mark exch seac_C + counttomark + { StandardEncoding exch get dup CharStrings exch get + dup type /integertype eq { load_C } { pop pop } ifelse + } repeat + pop % the mark + } bind def + +/seac_C % seac_C ..or nothing.. + { dup length _Cstring length le + { 4330 exch _Cstring .type1decrypt exch pop + dup dup length 2 sub 2 getinterval <0c06> eq % seac + { dup length + Private /lenIV known { Private /lenIV get } { 4 } ifelse + exch 1 index sub getinterval +% Parse the string just enough to extract the seac information. +% We assume that the only possible operators are hsbw, sbw, and seac, +% and that there are no 5-byte numbers. + mark 0 3 -1 roll + { exch + { { dup 32 lt + { pop 0 } + { dup 247 lt + { 139 sub 0 } + { dup 251 lt + { 247 sub 256 mul 108 add 1 1 } + { 251 sub -256 mul -108 add -1 1 } + ifelse + } + ifelse + } + ifelse + } % 0 + { mul add 0 } % 1 + } + exch get exec + } + forall pop + counttomark 1 add 2 roll cleartomark % pop all but achar bchar + } + { pop % not seac + } + ifelse + } + { pop % punt + } + ifelse + } bind def + +% Define replacement procedures for loading fonts. +% If DISKFONTS is true and the body of the font is not encrypted with eexec: +% - Prevent the CharStrings from being made read-only. +% - Substitute a different CharString-reading procedure. +% (eexec disables this because the implicit 'systemdict begin' hides +% the redefinitions that make the scheme work.) +% We assume that: +% - The magic procedures (-|, -!, |-, and |) are defined with +% executeonly or readonly; +% - The contents of the reading procedures are as defined in bdftops.ps; +% - The font includes the code +% /CharStrings readonly put +/.loadfontdict 6 dict def mark + /begin % push this dict after systemdict + { dup begin + //systemdict eq { //.loadfontdict begin } if + } bind + /end % match begin + { currentdict end + //.loadfontdict eq currentdict //systemdict eq and { end } if + } bind + /dict % leave room for FontFile, BuildChar, BuildGlyph + { 3 add dict + } bind + /executeonly % for reading procedures + { readonly + } + /noaccess % for Subrs strings and Private dictionary + { readonly + } + /readonly % for procedures and CharStrings dictionary + { % We want to take the following non-standard actions here: + % - If the operand is the CharStrings dictionary, do nothing; + % - If the operand is a number (a file position replacing the + % actual CharString), do nothing; + % - If the operand is either of the reading procedures (-| or -!), + % substitute a different one. + dup type /dicttype eq % CharStrings or Private + count 2 gt and + { 1 index /CharStrings ne { readonly } if } + { dup type /arraytype eq % procedure or data array + { dup length 5 ge 1 index xcheck and + { dup 0 get /string eq + 1 index 1 get /currentfile eq and + 1 index 2 get /exch eq and + 1 index 3 get dup /readstring eq exch /readhexstring eq or and + 1 index 4 get /pop eq and + { /cskip_C cvx 2 packedarray cvx + } + { readonly + } + ifelse + } + { readonly + } + ifelse + } + { dup type /stringtype eq % must be a Subr string + { readonly } + if + } + ifelse + } + ifelse + } bind + /definefont % to insert BuildChar/Glyph and change FontType + { dup /FontType get 1 eq + { dup /FontType 4 put + dup /BuildChar /build_C load put + dup /BuildGlyph /build_C load put + } + if definefont + } bind +counttomark 2 idiv { .loadfontdict 3 1 roll put } repeat pop +.loadfontdict readonly pop + +% Define the BuildChar and BuildGlyph procedures for modified fonts. +% A single procedure serves for both. +/build_C % build_C - + { 1 index begin + dup dup type /integertype eq { Encoding exch get } if + % Stack: font code|name name + dup CharStrings exch .knownget not + { 2 copy eq { exch pop /.notdef exch } if + QUIET not + { (Substituting .notdef for ) print = flush } + { pop } + ifelse + /.notdef CharStrings /.notdef get + } if + % Stack: font code|name name charstring + dup type /integertype eq + { load_C end build_C } + { end .type1execchar } + ifelse + } bind def diff --git a/pstoraster/gs_dps1.ps b/pstoraster/gs_dps1.ps new file mode 100644 index 0000000000..ebf5e98883 --- /dev/null +++ b/pstoraster/gs_dps1.ps @@ -0,0 +1,307 @@ +% Copyright (C) 1990, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Initialization file for analogs of Display PostScript functions +% that are also included in Level 2. +% When this is run, systemdict is still writable, +% but (almost) everything defined here goes into level2dict. + +level2dict begin + +% ------ Virtual memory ------ % + +/currentshared /.currentglobal load def +/scheck /.gcheck load def +%****** FOLLOWING IS WRONG ****** +/shareddict currentdict /globaldict .knownget not { 20 dict } if def + +% Global and LocalFontDirectory must remain in systemdict +% even if we temporarily exit Level 2 mode. + +end % level2dict +systemdict begin + +/SharedFontDirectory FontDirectory .gcheck + { .currentglobal false .setglobal + /LocalFontDirectory FontDirectory dup maxlength dict copy def + .setglobal FontDirectory + } + { /LocalFontDirectory FontDirectory def + 50 dict + } +ifelse def + +end % systemdict +level2dict begin + +% setshared must rebind FontDirectory to the appropriate one of +% Local or SharedFontDirectory. + +/.setglobal + { .setglobal + //systemdict /FontDirectory .currentglobal + { //SharedFontDirectory } + { //systemdict /LocalFontDirectory get } % can't embed ref to local VM + ifelse .forceput + } .bind odef % must bind .forceput and .setglobal + % even if NOBIND in effect +/setshared /.setglobal load def +.currentglobal setshared + +% ------ Fonts ------ % + +/selectfont + { exch findfont exch + dup type /arraytype eq { makefont } { scalefont } ifelse + setfont + } odef +% Undefinefont has to take local/global VM into account. +/undefinefont + { FontDirectory 1 index .undef + .currentglobal + { % Current mode is global; delete from local directory too. + //systemdict /LocalFontDirectory .knownget + { exch .undef } + { pop } + ifelse + } + { % Current mode is local; if there was a shadowed global + % definition, copy it into the local directory. + //systemdict /SharedFontDirectory .knownget + { 1 index .knownget + { FontDirectory 3 1 roll put } + { pop } + ifelse + } + if + } + ifelse + } odef + +% If we load a font into global VM within an inner save, the restore +% will delete it from FontDirectory but not from SharedFontDirectory. +% We have to handle this by making restore copy missing entries from +% SharedFontDirectory to FontDirectory. Since this could slow down restore +% considerably, we define a new operator .dictcopynew for this purpose. +% Furthermore, if FAKEFONTS is in effect, we want global real fonts to +% override fake local ones. We handle this by brute force. +/restore + { //restore + //systemdict /LocalFontDirectory get + FAKEFONTS + { mark + % We want to delete a fake font from the local directory + % iff the global directory now has no definition for it, + % or a non-fake definition. + 1 index dup + { % Stack: lfd mark lfd key ... lfd key value + length 1 gt + { % This is a real local definition; don't do anything. + pop + } + { % This is a fake local definition, check for global. + //SharedFontDirectory 1 index .knownget + { % A global definition exists, check for fake. + length 1 eq { pop } { 1 index } ifelse + } + { % No global definition, delete the local one. + 1 index + } + ifelse + } + ifelse + } forall + pop counttomark 2 idiv { .undef } repeat pop + } + if + //SharedFontDirectory exch .dictcopynew pop + } bind odef + +% ------ Halftones ------ % + +/.makestackdict + { { counttomark -1 roll } forall .dicttomark + } bind def +/currenthalftone + { mark .currenthalftone + { { exch pop } % halftone + { /HalftoneType 1 % screen + { /Frequency /Angle /SpotFunction } + .makestackdict + } + { /HalftoneType 2 % colorscreen + { /RedFrequency /RedAngle /RedSpotFunction + /GreenFrequency /GreenAngle /GreenSpotFunction + /BlueFrequency /BlueAngle /BlueSpotFunction + /GrayFrequency /GrayAngle /GraySpotFunction + } + .makestackdict + } + } + exch get exec + } odef +% Define sethalftone so it converts all other types to type 5. +/.sethalftoneRGBV % + { 4 -1 roll exch { 1 index exch get exch } forall 15 1 roll + 14 -2 roll mark 15 1 roll { /Gray /Blue /Green /Red } + { % stack: v0 v1 v2 type keys comp + mark + 2 index 0 get 8 -1 roll + 4 index 1 get 9 -1 roll + 6 index 2 get 10 -1 roll + % stack: type keys comp mark k0 v0 k1 v1 k2 v2 + /HalftoneType 10 index .dicttomark + counttomark 2 roll + } + forall pop pop + /Default 1 index .dicttomark .sethalftone5 + } bind def +/sethalftone + { dup /HalftoneType get 1 sub + { { mark /Default 2 index .dicttomark .sethalftone5 } + { 1 { /Frequency /Angle /SpotFunction } + { /RedFrequency /RedAngle /RedSpotFunction + /GreenFrequency /GreenAngle /GreenSpotFunction + /BlueFrequency /BlueAngle /BlueSpotFunction + /GrayFrequency /GrayAngle /GraySpotFunction + } .sethalftoneRGBV + } + { mark /Default 2 index .dicttomark .sethalftone5 } + { 3 { /Width /Height /Thresholds } + { /RedWidth /RedHeight /RedThresholds + /GreenWidth /GreenHeight /GreenThresholds + /BlueWidth /BlueHeight /BlueThresholds + /GrayWidth /GrayHeight /GrayThresholds + } .sethalftoneRGBV + } + { dup .sethalftone5 } + } exch get exec + } odef +% Redefine setscreen and setcolorscreen to recognize halftone dictionaries, +% and to insert the Frequency and Angle into Type 1 halftones, per +% Adobe TN 5085. +/.fixsethalftonescreen + { dup /HalftoneType get 1 eq + { dup wcheck not { dup length .copydict } if + dup /Frequency 4 index put + dup /Angle 3 index put + } + if + } bind def +/setscreen + { dup type /dicttype eq + { .fixsethalftonescreen sethalftone pop pop } + { //setscreen } + ifelse + } odef +/setcolorscreen + { dup type /dicttype eq + { .fixsethalftonescreen sethalftone 11 { pop } repeat } + { //setcolorscreen } + ifelse + } odef +% Redefine currentscreen and currentcolorscreen to extract the Frequency +% and Angle from Type 1 halftones, per Adobe TN 5085. +/.fixcurrenthalftonescreen % .fix... + { dup /HalftoneType get 1 eq + { dup /Frequency get 1 index /Angle get } + { 60 0 } + ifelse 3 2 roll + } bind def +/currentscreen + { .currenthalftone + { { .fixcurrenthalftonescreen } % halftone + { } % screen + { 12 3 roll 9 { pop } repeat % colorscreen + dup type /dicttype eq { .fixcurrenthalftonescreen } if + } + } + exch get exec + } odef +/currentcolorscreen + { .currenthalftone + { { .fixcurrenthalftonescreen 3 copy 6 copy } % halftone + { 3 copy 6 copy } % screen + { } % colorscreen + } + exch get exec + } odef + +% ------ User objects ------ % + +/.localarray where + { pop } + { /.localarray + { currentglobal false setglobal + exch array exch setglobal + } bind def + } +ifelse +/defineuserobject + { userdict /.UserObjects known + { 1 index userdict /.UserObjects get length ge + { 1 index 1 add .localarray userdict /.UserObjects get + 1 index copy pop + userdict /.UserObjects 3 -1 roll put + } + if + } + { userdict /.UserObjects 3 index 1 add .localarray put + } + ifelse + userdict /.UserObjects get 3 1 roll put + } odef +/execuserobject + { userdict /.UserObjects get exch get exec + } odef +/undefineuserobject + { userdict /.UserObjects get exch null put + } odef + +% ------ User paths ------ % + +% We define upath carefully so it won't leave garbage on the stack +% if an error occurs. +/upath + { [ + { 1 index {/ucache cvx} if true .pathbbox /setbbox cvx + {/moveto cvx} {/lineto cvx} {/curveto cvx} {/closepath cvx} + pathforall ] + } + .internalstopped + { cleartomark /upath load $error /errorname get signalerror + } + if cvx exch pop + } odef + +% Dummy definitions for cache control operators + +/ucachestatus + { mark 0 0 0 0 0 } odef +/setucacheparams + { cleartomark } odef + +% ------ Miscellaneous ------ % + +/undef /.undef load def + +end % level2dict diff --git a/pstoraster/gs_fform.ps b/pstoraster/gs_fform.ps new file mode 100644 index 0000000000..13d6547d2e --- /dev/null +++ b/pstoraster/gs_fform.ps @@ -0,0 +1,115 @@ +% Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% gs_fform.ps +% Monochrome Form caching implemented in PostScript. + +% This implementation is pretty unreasonable: +% - It doesn't remember transparent pixels. +% - It reduces everything to black and white. +% - It doesn't handle halftone or Pattern phasing. +% However, it's good enough to produce some useful output. + +% In order to prevent restore from clearing the cache, we explicitly +% push the cache entries on the stack before a restore and reinstall them. +/formcachedict 20 dict def +currentglobal true setglobal +/restore + { mark formcachedict { } forall + counttomark 1 add index { restore } .internalstopped + { cleartomark restore } + { counttomark 2 idiv { formcachedict 3 1 roll put } repeat pop pop } + ifelse + } bind odef + +/.form.buffer 65000 string def +/execform + { dup /Implementation known not + { dup /FormType get 1 ne { /rangecheck signalerror } if + formcachedict 1 index .knownget not + { currentglobal true setglobal + % Stack: form global + 10 dict + dup /ImageType 1 put + dup /ImageMatrix [0 0 0 0 0 0] put + dup /DataSource + { % Stack: y (impl is on dict stack) + Height 1 index sub + //.form.buffer length Width 7 add 8 idiv idiv .min + 1 index add exch + Device exch //.form.buffer copyscanlines + } + put + dup /BitsPerComponent 1 put + dup /Decode [0 1] put + dup /Device null put + % Stack: form global impl + formcachedict 3 index 2 index put + exch setglobal + } + if 1 index /Implementation 3 -1 roll put + } + if + gsave dup /Matrix get concat + dup /Implementation get + % Check whether we can use the cached value. + % Stack: form implementation + dup /ImageMatrix get matrix currentmatrix + true 0 1 3 + { % Stack: form impl cachemat curmat true index + 3 index 1 index get exch 3 index exch get ne { pop false exit } if + } + for % Stack: form impl cachemat curmat valid + exch pop exch pop not + { % Cache is invalid. Execute the Form and save the bits. + gsave begin + currentglobal exch true setglobal + ImageMatrix currentmatrix pop + dup /BBox get aload pop + exch 3 index sub exch 2 index sub rectclip + % Make the cache device. + clippath gsave matrix setmatrix pathbbox grestore + % We now have the bounding box in device space. + 2 { 4 -1 roll floor cvi } repeat + 2 { 4 -1 roll ceiling cvi } repeat + 2 index sub /Height exch def + 2 index sub /Width exch def + ImageMatrix aload pop + exch 7 index sub exch 6 index sub + 6 array astore + 3 1 roll pop pop + dup ImageMatrix copy pop + Width Height <00 ff> makeimagedevice + /Device 1 index def + nulldevice setdevice initgraphics + exch setglobal + dup dup /PaintProc get exec + nulldevice grestore currentdict end + } + if + % Now paint the bits. + % Stack: form implementation + /DeviceGray setcolorspace dup begin 0 exch image end pop + pop grestore + } odef + +setglobal diff --git a/pstoraster/gs_fonts.ps b/pstoraster/gs_fonts.ps new file mode 100644 index 0000000000..ddcd93cdb1 --- /dev/null +++ b/pstoraster/gs_fonts.ps @@ -0,0 +1,797 @@ +% Copyright (C) 1990, 1995, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Font initialization and management code. + +% Define the default font. +/defaultfontname /Courier def + +% Define the name of the font map file. +/defaultfontmap (Fontmap) def + +% ------ End of editable parameters ------ % + +% If DISKFONTS is true, we load individual CharStrings as they are needed. +% (This is intended primarily for machines with very small memories.) +% In this case, we define another dictionary, parallel to FontDirectory, +% that retains an open file for every font loaded. +/FontFileDirectory 10 dict def + +% Split up a search path into individual directories or files. +/.pathlist % .pathlist ... + { { dup length 0 eq { pop exit } if + .filenamelistseparator search not { exit } if + exch pop exch + } + loop + } bind def + +% Load a font name -> font file name map. +userdict /Fontmap FontDirectory maxlength dict put +/.loadFontmap % .loadFontmap - + { % We would like to simply execute .definefontmap as we read, + % but we have to maintain backward compatibility with an older + % specification that makes later entries override earlier. + 50 dict exch + { dup token not { closefile exit } if + % stack: fontname + % This is a hack to get around the absurd habit of MS-DOS editors + % of adding an EOF character at the end of the file. + dup (\032) eq { pop closefile exit } if + 1 index token not + { (Fontmap entry for ) print dup =only + ( has no associated file or alias name! Giving up.\n) print flush + {.loadFontmap} 0 get 1 .quit + } if + dup type dup /stringtype eq exch /nametype eq or not + { (Fontmap entry for ) print 1 index =only + ( has an invalid file or alias name! Giving up.\n) print flush + {.loadFontmap} 0 get 1 .quit + } if + % stack: dict file fontname filename|aliasname + % Read and pop tokens until a semicolon. + { 2 index token not + { (Fontmap entry for ) print 1 index =only + ( ends prematurely! Giving up.\n) print flush + {.loadFontmap} 0 get 1 .quit + } if + dup /; eq { pop 3 index 3 1 roll .growput exit } if + pop + } loop + } loop + { .definefontmap } forall + } bind def +% Add an entry in Fontmap. We redefine this if the Level 2 +% resource machinery is loaded. +/.definefontmap % .definefontmap - + { % Since Fontmap is global, make sure the values are storable. + .currentglobal 3 1 roll true .setglobal + dup type /stringtype eq + { dup .gcheck not { dup length string copy } if + } + if + Fontmap 3 -1 roll 2 copy .knownget + { % Add an element to the end of the existing value, + % unless it's the same as the current last element. + mark exch aload pop counttomark 4 add -1 roll + 2 copy eq { cleartomark pop pop } { ] readonly .growput } ifelse + } + { % Make a new entry. + mark 4 -1 roll ] readonly .growput + } + ifelse .setglobal + } bind def + +% Parse a font file just enough to find the FontName or FontType. +/.findfontvalue % .findfontvalue true + % .findfontvalue false + % Closes the file in either case. + { exch dup read not { -1 } if + 2 copy unread 16#80 eq + { dup (xxxxxx) readstring pop pop } % skip .PFB header + if + % Stack: key file + { dup token not { false exit } if % end of file + dup /eexec eq { pop false exit } if % reached eexec section + dup /Subrs eq { pop false exit } if % Subrs without eexec + dup /CharStrings eq { pop false exit } if % CharStrings without eexec + dup 3 index eq + { xcheck not { dup token exit } if } % found key + { pop } + ifelse + } loop + % Stack: key file value true (or) + % Stack: key file false + dup { 4 } { 3 } ifelse -2 roll closefile pop + } bind def +/.findfontname + { /FontName .findfontvalue + } bind def + +% If there is no FONTPATH, try to get one from the environment. +NOFONTPATH { /FONTPATH () def } if +/FONTPATH where + { pop } + { /FONTPATH (GS_FONTPATH) getenv not { () } if def } +ifelse +FONTPATH length 0 eq { (%END FONTPATH) .skipeof } if +/FONTPATH [ FONTPATH .pathlist ] def + +% Scan directories looking for plausible fonts. "Plausible" means that +% the file begins with %!PS-AdobeFont or %!FontType1, or with \200\001 +% followed by four arbitrary bytes and then either of these strings. +% To speed up the search, we skip any file whose name appears in +% the Fontmap (with any extension and upper/lower case variation) already, +% and any file whose extension definitely indicates it is not a font. +% +% NOTE: The current implementation of this procedure is somewhat Unix/DOS- +% specific. It assumes that '/' and '\' are directory separators, and that +% the part of a file name following the last '.' is the extension. +% +/.lowerstring % .lowerstring + { 0 1 2 index length 1 sub + { 2 copy get dup 65 ge exch 90 le and + { 2 copy 2 copy get 32 add put } + if pop + } + for + } bind def +/.splitfilename % .basename + { { (/) search { true } { (\\) search } ifelse + { pop pop } + { exit } + ifelse + } + loop + dup { (.) search { pop pop } { exit } ifelse } loop + 2 copy eq + { pop () } + { exch dup length 2 index length 1 add sub 0 exch getinterval exch } + ifelse +% Following is debugging code. +% (*** Split => ) print 2 copy exch ==only ( ) print ==only +% ( ***\n) print flush + } bind def +/.scanfontdict 1 dict def % establish a binding +/.scanfontbegin + { % Construct the table of all file names already in Fontmap. + currentglobal true setglobal + .scanfontdict dup maxlength Fontmap length 2 add .max .setmaxlength + Fontmap + { exch pop + { dup type /stringtype eq + { .splitfilename pop =string copy .lowerstring cvn + .scanfontdict exch true put + } + { pop + } + ifelse + } + forall + } + forall + setglobal + } bind def +/.scanfontskip mark + % Strings are converted to names anyway, so.... + /afm true + /bat true + /c true + /cmd true + /com true + /dll true + /doc true + /drv true + /exe true + /fon true + /fot true + /h true + /o true + /obj true + /pfm true + /txt true +.dicttomark def +/.scan1fontstring 128 string def +/.scanfontheaders [(%!PS-AdobeFont*) (%!FontType1*)] def +0 .scanfontheaders { length max } forall 6 add % extra for PFB header +/.scan1fontfirst exch string def +/.scanfontdir % .scanfontdir - + { currentglobal exch true setglobal + QUIET not { (Scanning ) print dup print ( for fonts...) print flush } if + (*) 2 copy .filenamedirseparator + dup (\\) eq { pop (\\\\) } if % double \ for pattern match + exch concatstrings concatstrings + 0 0 0 4 -1 roll % found scanned files + { % stack: + exch 1 add exch % increment filecount + dup .splitfilename .lowerstring + % stack: + % + .scanfontskip exch known exch .scanfontdict exch known or + { pop + % stack: + } + { 3 -1 roll 1 add 3 1 roll + % stack: + dup (r) { file } .internalstopped + { pop pop null () + % stack: + % null () + } + { + % On some platforms, the file operator will open directories, + % but an error will occur if we try to read from one. + % Handle this possibility here. + dup .scan1fontfirst { readstring } .internalstopped + { pop pop () } + { pop } + ifelse + % stack: + %
+ } + ifelse + % Check for PFB file header. + dup (\200\001????*) .stringmatch + { dup length 6 sub 6 exch getinterval } + if + % Check for font file headers. + false .scanfontheaders + { 2 index exch .stringmatch or + } + forall exch pop + { % stack: + % + dup 0 setfileposition .findfontname + { dup Fontmap exch known + { pop pop + } + { exch copystring exch + DEBUG { ( ) print dup =only } if + 1 index .definefontmap + .splitfilename pop true .scanfontdict 3 1 roll .growput + % Increment fontcount. + 3 -1 roll 1 add 3 1 roll + } + ifelse + } + { pop + } + ifelse + } + % .findfontname will have done a closefile in the above case. + { dup null eq { pop } { closefile } ifelse pop + } + ifelse + } + ifelse + } + .scan1fontstring filenameforall + QUIET + { pop pop pop } + { ( ) print =only ( files, ) print =only ( scanned, ) print + =only ( new fonts.\n) print flush + } + ifelse + setglobal + } bind def + +%END FONTPATH + +% Define definefont. This is a procedure built on a set of operators +% that do all the error checking and key insertion. +mark + /.buildfont0 where { pop 0 /.buildfont0 cvx } if + /.buildfont1 where { pop 1 /.buildfont1 cvx } if + /.buildfont3 where { pop 3 /.buildfont3 cvx } if + /.buildfont4 where { pop 4 /.buildfont4 cvx } if + /.buildfont42 where { pop 42 /.buildfont42 cvx } if +.dicttomark /buildfontdict exch def +/.growfontdict + { % Grow the font dictionary, if necessary, to ensure room for an + % added entry, making sure there is at least one slot left for FID. + dup maxlength 1 index length sub 2 lt + { dup dup wcheck + { .growdict } + { .growdictlength dict .copydict } + ifelse + } + { dup wcheck not { dup maxlength dict .copydict } if + } + ifelse + } bind def +/definefont + { 1 dict begin count /d exch def % save stack depth in case of error + { % Check for disabled platform fonts. + NOPLATFONTS + { % Make sure we leave room for FID. + .growfontdict dup /ExactSize 0 put + } + { % Hack: if the Encoding looks like it might be the + % Symbol or Dingbats encoding, load those now (for the + % benefit of platform font matching) just in case + % the font didn't actually reference them. + dup /Encoding get length 65 ge + { dup /Encoding get 64 get + dup /congruent eq { SymbolEncoding pop } if + /a9 eq { DingbatsEncoding pop } if + } + if + } + ifelse + dup /FontType get //buildfontdict exch get exec + DISKFONTS + { FontFileDirectory 2 index known + { dup /FontFile FontFileDirectory 4 index get .growput + } + if + } + if + readonly + } + stopped + { count d sub { pop } repeat end /invalidfont signalerror + } + { end % stack: name fontdict + % If the current allocation mode is global, also enter + % the font in LocalFontDirectory. + .currentglobal + { //systemdict /LocalFontDirectory .knownget + { 2 index 2 index .growput } + if + } + if + dup FontDirectory 4 -2 roll .growput + } + ifelse + } odef + +% Define a procedure for defining aliased fonts. +% We can't just copy the font (or even use the same font unchanged), +% because a significant number of PostScript files assume that +% the FontName of a font is the same as the font resource name or +% the key in [Shared]FontDirectory; on the other hand, some Adobe files +% rely on the FontName of a substituted font *not* being the same as +% the requested resource name. We address this issue heuristically: +% we substitute the new name iff the font name doesn't have MM in it. +/.aliasfont % .aliasfont + { .currentglobal 3 1 roll dup .gcheck .setglobal + dup length 2 add dict + dup 3 -1 roll { 1 index /FID eq { pop pop } { put dup } ifelse } forall + % Stack: global fontname newfont newfont. + % We might be defining a global font whose FontName + % is a local string. This is weird, but legal, + % and doesn't cause problems anywhere else. + % To avoid any possible problems, do a cvn. + 2 index =string cvs (MM) search + { pop pop pop pop + } + { /FontName exch dup type /stringtype eq { cvn } if put + } + ifelse + //systemdict /definefont get exec % Don't bind, since Level 2 + % redefines definefont + exch .setglobal + } odef % so findfont will bind it + +% Define .loadfontfile for loading a font. If we recognize Type 1 and/or +% TrueType fonts, gs_type1.ps and/or gs_ttf.ps will redefine this. +/.loadfontfile { cvx exec } bind def +/.loadfont + { % Some buggy fonts leave extra junk on the stack, + % so we have to make a closure that records the stack depth + % in a fail-safe way. + /.loadfontfile cvx count 1 sub 2 packedarray cvx exec + count exch sub { pop } repeat + } bind def + +% Find an alternate font to substitute for an unknown one. +% We go to some trouble to parse the font name and extract +% properties from it. Later entries take priority over earlier. +/.substitutefaces [ + % Guess at suitable substitutions for random unknown fonts. + [(Grot) /Times] + [(Roman) /Times] + [(Book) /NewCenturySchlbk] + % If the family name appears in the font name, + % use a font from that family. + [(Arial) /Helvetica] + [(Avant) /AvantGarde] + [(Bookman) /Bookman] + [(Century) /NewCenturySchlbk] + [(Cour) /Courier] + [(Geneva) /Helvetica] + [(Helv) /Helvetica] + [(NewYork) /Times] + [(Pala) /Palatino] + [(Sans) /Helvetica] + [(Schlbk) /NewCenturySchlbk] + [(Serif) /Times] + [(Swiss) /Helvetica] + [(Times) /Times] + % Substitute for Adobe Multiple Master fonts. + [(Myriad) /Times] + [(Minion) /Helvetica] + % Condensed or narrow fonts map to the only narrow family we have. + [(Cond) /Helvetica-Narrow] + [(Narrow) /Helvetica-Narrow] + % If the font wants to be monospace, use Courier. + [(Monospace) /Courier] + [(Typewriter) /Courier] +] readonly def +/.substituteproperties [ + [(It) 1] [(Oblique) 1] + [(Bd) 2] [(Bold) 2] [(bold) 2] [(Demi) 2] [(Heavy) 2] [(Sb) 2] +] readonly def +/.substitutefamilies mark + /AvantGarde + {/AvantGarde-Book /AvantGarde-BookOblique + /AvantGarde-Demi /AvantGarde-DemiOblique} + /Bookman + {/Bookman-Demi /Bookman-DemiItalic /Bookman-Light /Bookman-LightItalic} + /Courier + {/Courier /Courier-Oblique /Courier-Bold /Courier-BoldOblique} + /Helvetica + {/Helvetica /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique} + /Helvetica-Narrow + {/Helvetica-Narrow /Helvetica-Narrow-Oblique + /Helvetica-Narrow-Bold /Helvetica-Narrow-BoldOblique} + /NewCenturySchlbk + {/NewCenturySchlbk-Roman /NewCenturySchlbk-Italic + /NewCenturySchlbk-Bold /NewCenturySchlbk-BoldItalic} + /Palatino + {/Palatino-Roman /Palatino-Italic /Palatino-Bold /Palatino-BoldItalic} + /Times + {/Times-Roman /Times-Italic /Times-Bold /Times-BoldItalic} +.dicttomark readonly def +/.substitutefont % .substitutefont + { % Look for properties and/or a face name in the font name. + % If we find any, use Helvetica as the base font; + % otherwise, use the default font. + % Note that the "substituted" font name may be the same as + % the requested one; the caller must check this. + dup length string cvs + {defaultfontname /Helvetica-Oblique /Helvetica-Bold /Helvetica-BoldOblique} + exch 0 exch % stack: fontname facelist properties fontname + % Look for a face name. + .substitutefaces + { 2 copy 0 get search + { pop pop pop 1 get .substitutefamilies exch get + 4 -1 roll pop 3 1 roll + } + { pop pop + } + ifelse + } + forall + .substituteproperties + { 2 copy 0 get search + { pop pop pop 1 get 3 -1 roll or exch } + { pop pop } + ifelse + } + forall pop get + % If SUBSTFONT is defined, use it. + /SUBSTFONT where + { pop pop /SUBSTFONT load cvn } + { exec } + ifelse + % Only accept fonts known in the Fontmap. + Fontmap 1 index known not { pop defaultfontname } if + } bind def + +% If requested, make (and recognize) fake entries in FontDirectory for fonts +% present in Fontmap but not actually loaded. Thanks to Ray Johnston for +% the idea behind this code. +FAKEFONTS not { (%END FAKEFONTS) .skipeof } if + +% We use the presence or absence of the FontMatrix key to indicate whether +% a font is real or fake. + +/definefont % definefont + { dup /FontMatrix known not { /FontName get findfont } if + //definefont + } bind odef + +/scalefont % scalefont + { exch dup /FontMatrix known not { /FontName get findfont } if + exch //scalefont + } bind odef + +/makefont % makefont + { exch dup /FontMatrix known not { /FontName get findfont } if + exch //makefont + } bind def + +/setfont % setfont - + { dup /FontMatrix known not { /FontName get findfont } if + //setfont + } bind odef + +%END FAKEFONTS + +% Define findfont so it tries to load a font if it's not found. +% The Red Book requires that findfont be a procedure, not an operator. +/findfont + { mark exch + { .dofindfont + } stopped + { counttomark 1 sub { pop } repeat exch pop stop + } + { % Define any needed aliases. + counttomark 1 sub { .aliasfont } repeat + exch pop + } + ifelse + } bind def +% Check whether the font name we are about to look for is already on the list +% of aliases we're accumulating; if so, cause an error. +/.checkalias % -mark- ... .checkalias <> + { counttomark 1 sub -1 1 + { index 1 index eq + { pop QUIET not + { (Unable to substitute for font.\n) print flush + } if + /findfont cvx /invalidfont signalerror + } + if + } + for + } bind def +% Get a (non-fake) font if present in a FontDirectory. +/.fontknownget % .fontknownget true + % .fontknownget false + { .knownget + { FAKEFONTS + { dup /FontMatrix known { true } { pop false } ifelse } + { true } + ifelse + } + { false + } + ifelse + } bind def +% Do the work of findfont, including substitution, defaulting, and +% scanning of FONTPATH. +/.dofindfont % .dofindfont + { { .tryfindfont { exit } if + % We didn't find the font. If we haven't scanned + % all the directories in FONTPATH, scan the next one now, + % and look for the font again. + null 0 1 FONTPATH length 1 sub + { FONTPATH 1 index get null ne { exch pop exit } if pop + } + for dup null ne + { dup 0 eq { .scanfontbegin } if + FONTPATH 1 index get .scanfontdir + FONTPATH exch null put + % Start over with an empty alias list. + counttomark 1 sub { pop } repeat + .dofindfont exit + } + if pop + % No luck, substitute for the font. + dup defaultfontname eq + { QUIET not + { (Unable to load default font ) print + dup =only (! Giving up.\n) print flush + } + if /findfont cvx /invalidfont signalerror + } + if dup .substitutefont + 2 copy eq { pop defaultfontname } if + .checkalias + QUIET not + { (Substituting font ) print dup =only ( for ) print + 1 index =only (.\n) print flush + } + if + } + loop + } bind def +% Try to find a font using only the present contents of Fontmap. +/.tryfindfont % .tryfindfont true + % .tryfindfont false + { FontDirectory 1 index .fontknownget + { % Already loaded + exch pop true + } + { dup Fontmap exch .knownget not + { % Unknown font name + false + } + + { % Try each element of the Fontmap in turn. + false exch % (in case we exhaust the list) + { exch pop + dup type /nametype eq + { % Font alias + .checkalias .tryfindfont exit + } + { dup dup type dup /arraytype eq exch /packedarraytype eq or exch xcheck and + { % Font with a procedural definition + exec % The procedure will load the font. + % Check to make sure this really happened. + FontDirectory 1 index .knownget + { exch pop true exit } + if + } + { % Font file name + .loadfontloop { true exit } if + } + ifelse + } + ifelse false + } + forall + } + ifelse + } + ifelse + } bind def +% Attempt to load a font from a file. +/.loadfontloop % .loadfontloop true + % .loadfontloop false + { % See above regarding the use of 'loop'. + + { + % Can we open the file? + findlibfile not + { QUIET not + { (Can't find \(or can't open\) font file ) print dup print + (.\n) print flush + } + if pop false exit + } + if + + % Stack: fontname fontfilename fontfile + DISKFONTS + { .currentglobal true .setglobal + 2 index (r) file + FontFileDirectory exch 5 index exch .growput + .setglobal + } + if + QUIET not + { (Loading ) print 2 index =only + ( font from ) print 1 index print (... ) print flush + } + if + % If LOCALFONTS isn't set, load the font into local or global + % VM according to FontType; if LOCALFONTS is set, load the font + % into the current VM, which is what Adobe printers (but not + % DPS or CPSI) do. + LOCALFONTS { false } { /setglobal where } ifelse + { pop /FontType .findfontvalue { 1 eq } { false } ifelse + % .setglobal, like setglobal, aliases FontDirectory to + % GlobalFontDirectory if appropriate. However, we mustn't + % allow the current version of .setglobal to be bound in, + % because it's different depending on language level. + .currentglobal exch /.setglobal load exec + % Remove the fake definition, if any. + FontDirectory 3 index .undef + 1 index (r) file .loadfont FontDirectory exch + /.setglobal load exec + } + { .loadfont FontDirectory + } + ifelse + % Stack: fontname fontfilename fontdirectory + QUIET not + { //systemdict /level2dict known + { .currentglobal false .setglobal vmstatus + true .setglobal vmstatus 3 -1 roll pop + 6 -1 roll .setglobal 5 + } + { vmstatus 3 + } + ifelse { =only ( ) print } repeat + (done.\n) print flush + } if + + % Check to make sure the font was actually loaded. + dup 3 index .fontknownget + { 4 1 roll pop pop pop true exit } if + + % Maybe the file had a different FontName. + % See if we can get a FontName from the file, and if so, + % whether a font by that name exists now. + exch (r) file .findfontname + { 2 copy .fontknownget + { % Yes. Stack: origfontname fontdirectory filefontname fontdict + 3 -1 roll pop exch + QUIET + { pop + } + { (Using ) print =only + ( font for ) print 1 index =only + (.\n) print flush + } + ifelse true exit + } + if pop + } + if pop + + % The font definitely did not load correctly. + QUIET not + { (Loading ) print dup =only + ( font failed.\n) print flush + } if + false exit + + } loop % end of loop + + } bind def + +% Define a procedure to load all known fonts. +% This isn't likely to be very useful. +/loadallfonts + { Fontmap { pop findfont pop } forall + } bind def + +% If requested, load all the fonts defined in the Fontmap into FontDirectory +% as "fake" fonts i.e., font dicts with only FontName defined. +% We must ensure that this happens in both global and local directories. +/.definefakefonts + { + } + { (gs_fonts FAKEFONTS) VMDEBUG + 2 + { .currentglobal not .setglobal + Fontmap + { pop dup type /stringtype eq { cvn } if + FontDirectory 1 index known not + { 1 dict dup /FontName 3 index put + FontDirectory 3 1 roll put + } + if + } + forall + } + repeat + } +FAKEFONTS { exch } if pop def % don't bind, .current/setglobal get redefined + +% Install initial fonts from Fontmap. +/.loadinitialfonts + { NOFONTMAP not + { /FONTMAP where + { pop [ FONTMAP .pathlist ] + { dup VMDEBUG findlibfile + { exch pop .loadFontmap } + { /undefinedfilename signalerror } + ifelse + } + } + { LIBPATH + { defaultfontmap 2 copy .filenamedirseparator + exch concatstrings concatstrings dup VMDEBUG + (r) { file } .internalstopped + { pop pop } { .loadFontmap } ifelse + } + } + ifelse forall + } + if + .definefakefonts + } def % don't bind, .current/setglobal get redefined diff --git a/pstoraster/gs_init.ps b/pstoraster/gs_init.ps new file mode 100644 index 0000000000..452e9f6790 --- /dev/null +++ b/pstoraster/gs_init.ps @@ -0,0 +1,1271 @@ +% Copyright (C) 1989, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Initialization file for the interpreter. +% When this is run, systemdict is still writable. + +% Comment lines of the form +% %% Replace +% indicate places where the next lines should be replaced by +% the contents of , when creating a single merged init file. + +% The interpreter can call out to PostScript code. All procedures +% called in this way, and no other procedures defined in these +% initialization files, have names that begin with %, e.g., +% (%Type1BuildChar) cvn. + +% Check the interpreter revision. NOTE: the interpreter code requires +% that the first non-comment token in this file be an integer. +40000 +dup revision ne + { (pstoraster: Interpreter revision \() print revision 10 string cvs print + (\) does not match gs_init.ps revision \() print 10 string cvs print + (\).\n) print flush null 1 .quit + } +if pop + +% Acquire userdict, and set its length if necessary. +/userdict where + { pop userdict maxlength 0 eq } + { true } +ifelse + { % userdict wasn't already set up by iinit.c. + /userdict + currentdict dup 200 .setmaxlength % userdict + systemdict begin def % can't use 'put', userdict is local + } + { systemdict begin + } +ifelse + +% Define dummy local/global operators if needed. +systemdict /.setglobal known + { true .setglobal + } + { /.setglobal { pop } bind def + /.currentglobal { false } bind def + /.gcheck { pop false } bind def + } +ifelse + +% Define .languagelevel if needed. +systemdict /.languagelevel known not { /.languagelevel 1 def } if + +% Optionally choose a default paper size other than U.S. letter. +% (a4) /PAPERSIZE where { pop pop } { /PAPERSIZE exch def } ifelse + +% Turn on array packing for the rest of initialization. +true setpacking + +% Define the old MS-DOS EOF character as a no-op. +% This is a hack to get around the absurd habit of MS-DOS editors +% of adding an EOF character at the end of the file. +<1a> cvn { } def + +% Acquire the debugging flags. +currentdict /DEBUG known /DEBUG exch def + /VMDEBUG + DEBUG {{print mark + systemdict /level2dict known + { .currentglobal dup false .setglobal vmstatus + true .setglobal vmstatus 3 -1 roll pop + 6 -2 roll pop .setglobal + } + { vmstatus 3 -1 roll pop + } + ifelse usertime 16#fffff and counttomark + { ( ) print ( ) cvs print } + repeat pop + ( ) print systemdict length ( ) cvs print + ( ) print countdictstack ( ) cvs print + ( <) print count ( ) cvs print (>\n) print flush + }} + {{pop + }} + ifelse + def + +currentdict /DELAYBIND known /DELAYBIND exch def +currentdict /DISKFONTS known /DISKFONTS exch def +currentdict /ESTACKPRINT known /ESTACKPRINT exch def +currentdict /FAKEFONTS known /FAKEFONTS exch def +currentdict /FIXEDMEDIA known /FIXEDMEDIA exch def +currentdict /FIXEDRESOLUTION known /FIXEDRESOLUTION exch def +currentdict /LOCALFONTS known /LOCALFONTS exch def +currentdict /NOBIND known /NOBIND exch def +/.bind /bind load def +NOBIND { /bind { } def } if +currentdict /NOCACHE known /NOCACHE exch def +currentdict /NOCIE known /NOCIE exch def +currentdict /NODISPLAY known not /DISPLAYING exch def +currentdict /NOFONTMAP known /NOFONTMAP exch def +currentdict /NOFONTPATH known /NOFONTPATH exch def +currentdict /NOGC known /NOGC exch def +currentdict /NOPAUSE known /NOPAUSE exch def +currentdict /NOPLATFONTS known /NOPLATFONTS exch def +currentdict /NOPROMPT known /NOPROMPT exch def +% The default value of ORIENT1 is true, not false. +currentdict /ORIENT1 known not { /ORIENT1 true def } if +currentdict /OSTACKPRINT known /OSTACKPRINT exch def +currentdict /OUTPUTFILE known % obsolete + { /OutputFile /OUTPUTFILE load def + currentdict /OUTPUTFILE .undef + } if +currentdict /QUIET known /QUIET exch def +currentdict /SAFER known /SAFER exch def +currentdict /SHORTERRORS known /SHORTERRORS exch def +currentdict /WRITESYSTEMDICT known /WRITESYSTEMDICT exch def + +% Acquire environment variables. +currentdict /DEVICE known not + { (GS_DEVICE) getenv { /DEVICE exch def } if } if + +(START) VMDEBUG + +% Open the standard files, so they will be open at the outermost save level. +(%stdin) (r) file pop +(%stdout) (w) file pop +(%stderr) (w) file pop + +% Define a procedure for skipping over an unneeded section of code. +% This avoids allocating space for the skipped procedures. +% We can't use readline, because that imposes a line length limit. +/.skipeof % .skipeof - + { currentfile exch 1 exch .subfiledecode flushfile + } bind def + +% If we're delaying binding, remember everything that needs to be bound later. +DELAYBIND NOBIND not and + { .currentglobal false .setglobal + userdict /.delaybind 1500 array put + .setglobal + userdict /.delaycount 0 put + % When we've done the delayed bind, we want to stop saving. + % Detect this by the disappearance of .delaybind. + /bind + { userdict /.delaybind .knownget + { .delaycount 2 index put + userdict /.delaycount .delaycount 1 add put + } + { .bind + } + ifelse + } bind def + } if + +% Define procedures to assist users who don't read the documentation. +userdict begin +/help + { (Enter PostScript commands. '(filename) run' runs a file, 'quit' exits.\n) + print flush + } bind def +/? /help load def +end + +% Define =string, which is used by some PostScript programs even though +% it isn't documented anywhere. +% Put it in userdict so that each context can have its own copy. +userdict /=string 256 string put + +% Print the greeting. + +/printgreeting + { mark + product (Ghostscript) search + { pop pop pop + (This software comes with NO WARRANTY: see the file COPYING for details.\n) + } + { pop + } + ifelse + (\n) copyright + (\)\n) revisiondate 100 mod (-) + revisiondate 100 idiv 100 mod (-) + revisiondate 10000 idiv ( \() + revision 10 mod + revision 10 idiv 10 mod (.) + revision 100 idiv ( ) + product + counttomark + { (%stderr) (w) file exch false .writecvp + } repeat pop + } bind def + +QUIET not { printgreeting flush } if + +% Define a special version of def for making operator procedures. +/odef % odef - + { 1 index exch .makeoperator def + } .bind def + +%**************** BACKWARD COMPATIBILITY +/getdeviceprops + { null .getdeviceparams + } bind odef +/.putdeviceprops + { null true counttomark 1 add 3 roll .putdeviceparams + dup type /booleantype ne + { dup mark eq { /unknown /rangecheck } if + counttomark 4 add 1 roll cleartomark pop pop pop + /.putdeviceprops load exch signalerror + } + if + } bind odef +/.devicenamedict 1 dict dup /OutputDevice dup put def +/.devicename + { //.devicenamedict .getdeviceparams exch pop exch pop + } bind odef +/max { .max } bind def +/min { .min } bind def +/.currentfilladjust { .currentfilladjust2 pop } bind odef +/.setfilladjust { dup .setfilladjust2 } bind odef +/.writecvs { false .writecvp } bind odef + +% Define predefined procedures substituting for operators, +% in alphabetical order. + +userdict /#copies 1 put +% Adobe implementations don't accept /[ or /], so we don't either. +([) cvn + /mark load def +(]) cvn + {counttomark array astore exch pop} odef +/abs {dup 0 lt {neg} if} odef +% .beginpage is an operator in Level 2. +/.beginpage { } odef +/copypage + { 1 .endpage + { .currentnumcopies false .outputpage + (>>copypage, press to continue<<\n) .confirm + } + if .beginpage + } odef +% .currentnumcopies is redefined in Level 2. +/.currentnumcopies { #copies } odef +/setcolorscreen where { pop % not in all Level 1 configurations + /currentcolorscreen + { .currenthalftone + { { 60 exch 0 exch 3 copy 6 copy } % halftone - not possible + { 3 copy 6 copy } % screen + { } % colorscreen + } + exch get exec + } odef +} if +/currentscreen + { .currenthalftone + { { 60 exch 0 exch } % halftone - not possible + { } % screen + { 12 3 roll 9 { pop } repeat } % colorscreen + } + exch get exec + } odef +/.echo /echo load def +userdict /.echo.mode true put +/echo {dup /.echo.mode exch store .echo} odef +/eexec + { 55665 //filterdict /eexecDecode get exec + cvx //systemdict begin stopped + % Only pop systemdict if it is still the top element, + % because this is apparently what Adobe interpreters do. + currentdict //systemdict eq { end } if + { stop } if + } odef +% .endpage is an operator in Level 2. +/.endpage { 2 ne } odef +% erasepage mustn't use gsave/grestore, because we call it before +% the graphics state stack has been fully initialized. +/erasepage + { /currentcolor where + { pop currentcolor currentcolorspace { setcolorspace setcolor } } + { /currentcmykcolor where + { pop currentcmykcolor { setcmykcolor } } + { currentrgbcolor { setrgbcolor } } + ifelse + } + ifelse 1 setgray .fillpage exec + } odef +/executive + { { prompt + { (%statementedit) (r) file } stopped + { pop pop $error /errorname get /undefinedfilename eq + { .clearerror exit } if % EOF + handleerror null % ioerror?? + } + if + cvx execute + } loop + } odef +/filter + { //filterdict 1 index .knownget + { exch pop exec } + { /filter load /undefined signalerror } + ifelse + } odef +/handleerror + { errordict /handleerror get exec } bind def +/identmatrix [1.0 0.0 0.0 1.0 0.0 0.0] readonly def +/identmatrix + { //identmatrix exch copy } odef +/initgraphics + { initmatrix newpath initclip + 1 setlinewidth 0 setlinecap 0 setlinejoin + [] 0 setdash 0 setgray 10 setmiterlimit + } odef +/languagelevel 1 def % gs_lev2.ps may change this +/makeimagedevice { false makewordimagedevice } odef +/matrix { 6 array identmatrix } odef +/pathbbox { false .pathbbox } odef +/prompt { flush flushpage + (GS) print + count 0 ne { (<) print count =only } if + (>) print flush + } bind def +/pstack { 0 1 count 3 sub { index == } for } bind def +/putdeviceprops + { .putdeviceprops { erasepage } if } odef +/quit { /quit load 0 .quit } odef +/run { dup type /filetype ne { (r) file } if + % We must close the file when execution terminates, + % regardless of the state of the stack, + % and then propagate an error, if any. + cvx .runexec + } odef +/setdevice + { .setdevice { erasepage } if } odef +/showpage + { 0 .endpage + { .currentnumcopies true .outputpage + (>>showpage, press to continue<<\n) .confirm + erasepage + } + if initgraphics .beginpage + } odef +% Code output by Adobe Illustrator relies on the fact that +% `stack' is a procedure, not an operator!!! +/stack { 0 1 count 3 sub { index = } for } bind def +/start { executive } def +/stop { true .stop } odef +% Internal uses of stopped that aren't going to do a stop if an error occurs +% should use .internalstopped to avoid setting newerror et al. +/stopped { false .stopped } odef +/.internalstopped { null .stopped null ne } bind def +/store { 1 index where { 3 1 roll put } { def } ifelse } odef +% When running in Level 1 mode, this interpreter is supposed to be +% compatible with PostScript "version" 54.0 (I think). +/version (54.0) def + +% internaldict is defined in systemdict, but is allocated in local VM. +systemdict /internaldict .knownget not { 0 } if type /operatortype ne + { .currentglobal false .setglobal + //systemdict /internaldict known not { /internaldict 5 dict def } if + /internaldict + [ /dup load 1183615869 /eq load + [ /pop load internaldict ] cvx + [ /internaldict /cvx load /invalidaccess /signalerror cvx ] cvx + /ifelse load + ] cvx bind odef + .setglobal + } if + +% Define some additional built-in procedures (beyond the ones defined by +% the PostScript Language Reference Manual). +% Warning: these are not guaranteed to stay the same from one release +% to the next! +/concatstrings + { exch dup length 2 index length add string % str2 str1 new + dup dup 4 2 roll copy % str2 new new new1 + length 4 -1 roll putinterval + } bind def +/copyarray + { dup length array copy } bind def +% Copy a dictionary per the Level 2 spec even in Level 1. +/.copydict % .copydict + { dup 3 -1 roll { put dup } forall pop } bind def +/copystring + { dup length string copy } bind def +/finddevice + { //systemdict /devicedict get exch get + dup 1 get null eq + { % This is the first request for this type of device. + % Create a default instance now. + % Stack: [proto null] + .currentglobal true .setglobal exch + dup dup 0 get copydevice 1 exch put + exch .setglobal + } + if 1 get + } bind def +/.growdictlength % get size for growing a dictionary + { length 3 mul 2 idiv 1 add + } bind def +/.growdict % grow a dictionary + { dup .growdictlength .setmaxlength + } bind def +/.growput % put, grow the dictionary if needed + { 2 index length 3 index maxlength eq + { 3 copy pop known not { 2 index .growdict } if + } if + put + } bind def +/.packtomark + { counttomark packedarray exch pop } bind def +/ppstack + { 0 1 count 3 sub { index === } for } bind def +/runlibfile + { findlibfile + { exch pop run } + { /undefinedfilename signalerror } + ifelse + } bind def +/selectdevice + { finddevice setdevice .setdefaultscreen } bind def +/signalerror % signalerror - + { errordict exch get exec } bind def + +% Define the =[only] procedures. Also define =print, +% which is used by some PostScript programs even though +% it isn't documented anywhere. +/write=only + { { .writecvs } .internalstopped + { pop (--nostringval--) writestring + } + if + } bind def +/write= + { 1 index exch write=only (\n) writestring + } bind def +/=only { (%stderr) (w) file exch write=only } bind def +/= { =only (\n) print } bind def +/=print /=only load def +% Temporarily define == as = for the sake of runlibfile0. +/== /= load def + +% Define procedures for getting and setting the current device resolution. + +/gsgetdeviceprop % gsgetdeviceprop + { 2 copy mark exch null .dicttomark .getdeviceparams + dup mark eq % if true, not found + { pop dup /undefined signalerror } + { 5 1 roll pop pop pop pop } + ifelse + } bind def +/gscurrentresolution % - gscurrentresolution <[xres yres]> + { currentdevice /HWResolution gsgetdeviceprop + } bind def +/gssetresolution % <[xres yres]> gssetresolution - + { 2 array astore mark exch /HWResolution exch + currentdevice copydevice putdeviceprops setdevice + } bind def + +% Define auxiliary procedures needed for the above. +/shellarguments % -> shell_arguments true (or) false + { /ARGUMENTS where + { /ARGUMENTS get dup type /arraytype eq + { aload pop /ARGUMENTS null store true } + { pop false } + ifelse } + { false } ifelse + } bind def +/.confirm + { DISPLAYING NOPAUSE not and + { % Print a message (unless NOPROMPT is true) + % and wait for the user to type something. + % If the user just types a newline, flush it. + NOPROMPT { pop } { print flush } ifelse + .echo.mode false echo + (%stdin) (r) file dup read + { dup (\n) 0 get eq { pop pop } { unread } ifelse } + { pop } + ifelse echo + } + { pop + } + ifelse + } bind def + +% Define the procedure used by .runfile, .runstdin and .runstring +% for executing user input. +% This is called with a procedure or executable file on the operand stack. +/execute + { stopped + $error /newerror get and + { handleerror flush + } if + } odef +% Define an execute analogue of runlibfile0. +/execute0 + { stopped + $error /newerror get and + { handleerror flush /execute0 cvx 1 .quit + } if + } bind def +% Define the procedure that the C code uses for running files +% named on the command line. +/.runfile { { runlibfile } execute } def +% Define the procedure that the C code uses for running piped input. +/.runstdin { (%stdin) (r) file cvx execute0 } bind def +% Define the procedure that the C code uses for running commands +% given on the command line with -c. +/.runstring { cvx execute } def + +% Define a special version of runlibfile that aborts on errors. +/runlibfile0 + { cvlit dup /.currentfilename exch def + { findlibfile not { stop } if } + stopped + { (Can't find \(or open\) initialization file ) print + .currentfilename == flush /runlibfile0 cvx 1 .quit + } if + exch pop cvx stopped + { (While reading ) print .currentfilename print (:\n) print flush + handleerror /runlibfile0 1 .quit + } if + } bind def +% Temporarily substitute it for the real runlibfile. +/.runlibfile /runlibfile load def +/runlibfile /runlibfile0 load def + +% Create the error handling machinery. +% Define the standard error handlers. +% The interpreter has created the ErrorNames array. +/.unstoppederrorhandler % .unstoppederrorhandler - + { % This is the handler that gets used for recursive errors, + % or errors outside the scope of a 'stopped'. + 2 copy SHORTERRORS + { (%%[ Error: ) print =only flush + (; OffendingCommand: ) print =only ( ]%%\n) print + } + { (Unrecoverable error: ) print =only flush + ( in ) print = flush + count 2 gt + { (Operand stack:\n ) print + 2 1 count 3 sub { ( ) print index =only flush } for + (\n) print flush + } if + } + ifelse + -1 0 1 //ErrorNames length 1 sub + { dup //ErrorNames exch get 3 index eq + { not exch pop exit } { pop } ifelse + } + for exch pop .quit + } bind def +/.errorhandler % .errorhandler - + { % Detect an internal 'stopped'. + .instopped { null eq { pop pop stop } if } if + $error /.inerror get .instopped { pop } { pop true } ifelse + { .unstoppederrorhandler + } if % detect error recursion + $error /globalmode .currentglobal false .setglobal put + $error /.inerror true put + $error /newerror true put + $error exch /errorname exch put + $error exch /command exch put + $error /recordstacks get $error /errorname get /VMerror ne and + { % Attempt to store the stack contents atomically. + count array astore dup $error /ostack 4 -1 roll + countexecstack array execstack $error /estack 3 -1 roll + countdictstack array dictstack $error /dstack 3 -1 roll + put put put aload pop + } + { $error /dstack .undef + $error /estack .undef + $error /ostack .undef + } + ifelse + $error /position currentfile status + { currentfile { fileposition } .internalstopped { pop null } if + } + { % If this was a scanner error, the file is no longer current, + % but the command holds the file, which may still be open. + $error /command get dup type /filetype eq + { { fileposition } .internalstopped { pop null } if } + { pop null } + ifelse + } + ifelse put + % During initialization, we don't reset the allocation + % mode on errors. + $error /globalmode get $error /.nosetlocal get and .setglobal + $error /.inerror false put + stop + } bind def +% Define the standard handleerror. We break out the printing procedure +% (.printerror) so that it can be extended for binary output +% if the Level 2 facilities are present. + /.printerror + { $error begin + /command load errorname SHORTERRORS + { (%%[ Error: ) print =only flush + (; OffendingCommand: ) print =only + currentdict /errorinfo .knownget + { (;\nErrorInfo:) print + dup type /arraytype eq + { { ( ) print =only } forall } + { ( ) print =only } + ifelse + } if + ( ]%%\n) print flush + } + { (Error: ) print ==only flush + ( in ) print ==only flush + currentdict /errorinfo .knownget + { (\nAdditional information: ) print ==only flush + } if + .printerror_long + } + ifelse + .clearerror + end + flush + } bind def + /.printerror_long % long error printout, + % $error is on the dict stack + { % Push the (anonymous) stack printing procedure. + % <==flag> proc + { + currentdict exch .knownget % stackname defined in $error? + { + 4 1 roll % stack: <==flag> + errordict exch .knownget % overridename defined? + { + exch pop exch pop exec % call override with + } + { + exch print exch % print heading. stack <==flag> + 1 index not { (\n) print } if + { 1 index { (\n ) } { ( ) } ifelse print + dup type /dicttype eq + { + (--dict:) print + dup rcheck + { dup length =only (/) print maxlength =only } + { pop } + ifelse + (--) print + } + { + dup type /stringtype eq 2 index or + { ===only } { =only } ifelse + } ifelse + } forall + pop + } + ifelse % overridden + } + { pop pop pop + } + ifelse % stack known + } + + (\nOperand stack:) OSTACKPRINT /.printostack /ostack 4 index exec + (\nExecution stack:) ESTACKPRINT /.printestack /estack 4 index exec + (\nBacktrace:) true /.printbacktrace /backtrace 4 index exec + (\nDictionary stack:) false /.printdstack /dstack 4 index exec + (\n) print + pop % printing procedure + + errorname /VMerror eq + { (VM status:) print mark vmstatus + counttomark { ( ) print counttomark -1 roll dup =only } repeat + cleartomark (\n) print + } if + + .languagelevel 2 ge + { (Current allocation mode is ) print + globalmode { (global\n) } { (local\n) } ifelse print + } if + + .oserrno dup 0 ne + { (Last OS error: ) print + errorname /VMerror ne + { dup .oserrorstring { = pop } { = } ifelse } + { = } + ifelse + } + { pop + } + ifelse + + position null ne + { (Current file position is ) print position = } + if + + } bind def +% Define a procedure for clearing the error indication. +/.clearerror + { $error /newerror false put + $error /errorinfo .undef + 0 .setoserrno + } bind def + +% Define $error. This must be in local VM. +.currentglobal false .setglobal +/$error 40 dict def % newerror, errorname, command, errorinfo, + % ostack, estack, dstack, recordstacks, + % binary, globalmode, + % .inerror, .nosetlocal, position, + % plus extra space for badly designed error handers. +$error begin + /newerror false def + /recordstacks true def + /binary false def + /globalmode .currentglobal def + /.inerror false def + /.nosetlocal true def + /position null def +end +% Define errordict similarly. It has one entry per error name, +% plus handleerror. +/errordict ErrorNames length 1 add dict def +.setglobal % contents of errordict are global +errordict begin + ErrorNames + { mark 1 index systemdict /.errorhandler get /exec load .packtomark cvx def + } forall +% The handlers for interrupt and timeout are special; there is no +% 'current object', so they push their own name. + { /interrupt /timeout } + { mark 1 index dup systemdict /.errorhandler get /exec load .packtomark cvx def + } forall +/handleerror + { //systemdict /.printerror get exec + } bind def +end + +% Define the [write]==[only] procedures. +/.dict 26 dict dup +begin def + /.cvp {1 index exch .writecvs} bind def + /.nop {exch pop .p} bind def + /.p {1 index exch writestring} bind def + /.p1 {2 index exch writestring} bind def + /.p2 {3 index exch writestring} bind def + /.print + { dup type .dict exch .knownget + { dup type /stringtype eq { .nop } { exec } ifelse } + { (-) .p1 type .cvp (-) .p } + ifelse + } bind def + /.pstring + { { dup dup 32 lt exch 127 ge or + { (\\) .p1 2 copy -6 bitshift 48 add write + 2 copy -3 bitshift 7 and 48 add write + 7 and 48 add + } + { dup dup -2 and 40 eq exch 92 eq or {(\\) .p1} if + } + ifelse 1 index exch write + } + forall + } bind def + /booleantype /.cvp load def + /conditiontype (-condition-) def + /devicetype (-device-) def + /dicttype (-dict-) def + /filetype (-file-) def + /fonttype (-fontID-) def + /gstatetype (-gstate-) def + /integertype /.cvp load def + /locktype (-lock-) def + /marktype (-mark-) def + /nulltype (null) def + /realtype {1 index exch true .writecvp} bind def + /savetype (-save-) def + /nametype + {dup xcheck not {(/) .p1} if + 1 index exch .writecvs} bind def + /arraytype + {dup rcheck + {() exch dup xcheck + {({) .p2 + {exch .p1 + 1 index exch .print pop ( )} forall + (})} + {([) .p2 + {exch .p1 + 1 index exch .print pop ( )} forall + (])} + ifelse exch pop .p} + {(-array-) .nop} + ifelse} bind def + /operatortype + {(--) .p1 .cvp (--) .p} bind def + /packedarraytype + { dup rcheck + { arraytype } + { (-packedarray-) .nop } + ifelse + } bind def + /stringtype + { dup rcheck + { (\() .p1 dup length 200 le + { .pstring } + { 0 200 getinterval .pstring (...) .p } + ifelse (\)) .p + } + { (-string-) .nop + } + ifelse + } bind def +{//.dict begin .print pop end} + bind +end + +/write==only exch def +/write== {1 index exch write==only (\n) writestring} bind def +/==only { (%stderr) (w) file exch write==only } bind def +/== {==only (\n) print} bind def + +% Define [write]===[only], an extension that prints dictionaries +% in readable form and doesn't truncate strings. +/.dict /write==only load 0 get dup length dict .copydict dup +begin def + /dicttype + { dup rcheck + { (<< ) .p1 + { 2 index 3 -1 roll .print pop ( ) .p1 + 1 index exch .print pop ( ) .p + } + forall (>>) .p + } + { (-dict-) .nop + } + ifelse + } bind def + /stringtype + { dup rcheck + { (\() .p1 .pstring (\)) .p } + { (-string-) .nop } + ifelse + } bind def + +{//.dict begin .print pop end} + bind +end + +/write===only exch def +/write=== {1 index exch write===only (\n) writestring} bind def +/===only { (%stderr) (w) file exch write===only } bind def +/=== { ===only (\n) print } bind def + +(END PROCS) VMDEBUG + +% Define the font directory. +/FontDirectory false .setglobal 100 dict true .setglobal def + +% Define the encoding dictionary. +/EncodingDirectory 10 dict def % enough for Level 2 + PDF standard encodings + +% Define .findencoding. (This is redefined in Level 2.) +/.findencoding + { //EncodingDirectory exch get exec + } bind def +/.defineencoding + { //EncodingDirectory 3 1 roll put + } bind def +% If we've got the composite font extensions, define findencoding. +/rootfont where { pop /findencoding { .findencoding } odef } if + +% Load StandardEncoding. +%% Replace 1 (gs_std_e.ps) +(gs_std_e.ps) dup runlibfile VMDEBUG + +% Load ISOLatin1Encoding. +%% Replace 1 (gs_iso_e.ps) +(gs_iso_e.ps) dup runlibfile VMDEBUG + +% Define stubs for the Symbol and Dingbats encodings. +% Note that the first element of the procedure must be the file name, +% since gs_lev2.ps extracts it to set up the Encoding resource category. + + /SymbolEncoding { /SymbolEncoding .findencoding } bind def +%% Replace 3 (gs_sym_e.ps) + EncodingDirectory /SymbolEncoding + { (gs_sym_e.ps) //systemdict begin runlibfile SymbolEncoding end } + bind put + + /DingbatsEncoding { /DingbatsEncoding .findencoding } bind def +%% Replace 3 (gs_dbt_e.ps) + EncodingDirectory /DingbatsEncoding + { (gs_dbt_e.ps) //systemdict begin runlibfile DingbatsEncoding end } + bind put + +(END FONTDIR/ENCS) VMDEBUG + +% Construct a dictionary of all available devices. +% These are (read-only) device prototypes that can't be +% installed or have their parameters changed. For this reason, +% the value in the dictionary is actually a 2-element writable array, +% to allow us to create a default instance of the prototype on demand. + + % Loop until the .getdevice gets a rangecheck. +errordict /rangecheck 2 copy get +errordict /rangecheck { pop stop } put % pop the command + 0 { {dup .getdevice exch 1 add} loop} null .stopped pop + 1 add dict /devicedict 1 index def + begin % 2nd copy of count is on stack + { dup .devicename exch + dup wcheck { dup } { null } ifelse 2 array astore def + } repeat + end +put % errordict /rangecheck +.clearerror +/devicenames devicedict { pop } forall devicedict length packedarray def + +% Determine the default device. +/defaultdevice DISPLAYING + { systemdict /DEVICE .knownget + { devicedict 1 index known not + { (Unknown device: ) print = + flush /defaultdevice cvx 1 .quit + } + if + } + { 0 .getdevice .devicename + } + ifelse + } + { /nullpage + } +ifelse +/.defaultdevicename 1 index def +finddevice % make a copy +def +devicedict /Default devicedict .defaultdevicename get put + +(END DEVS) VMDEBUG + +% Define statusdict, for the benefit of programs +% that think they are running on a LaserWriter or similar printer. +%% Replace 1 (gs_statd.ps) +(gs_statd.ps) runlibfile + +(END STATD) VMDEBUG + +% Load the standard font environment. +%% Replace 1 (gs_fonts.ps) +(gs_fonts.ps) runlibfile + +(END GS_FONTS) VMDEBUG + +% Load the initialization files for optional features. +%% Replace 4 INITFILES +systemdict /INITFILES known + { INITFILES { dup runlibfile VMDEBUG } forall + } +if + +% If Level 2 functionality is implemented, enable it now. +/.setlanguagelevel where + { pop 2 .setlanguagelevel + } if + +(END INITFILES) VMDEBUG + +% Create a null font. This is the initial font. +8 dict dup begin + /FontMatrix [ 1 0 0 1 0 0 ] readonly def + /FontType 3 def + /FontName () def + /Encoding StandardEncoding def + /FontBBox { 0 0 0 0 } readonly def % executable is bogus, but customary ... + /BuildChar { pop pop 0 0 setcharwidth } bind def + /PaintType 0 def % shouldn't be needed! +end +/NullFont exch definefont setfont + +% Define NullFont as the font. +/NullFont currentfont def + +% Load initial fonts from FONTPATH directories, Fontmap file, +% and/or .getccfont as appropriate. +.loadinitialfonts + +% Remove NullFont from FontDirectory, so it can't be accessed by mistake. +FontDirectory /NullFont .undef + +(END FONTS) VMDEBUG + +% Restore the real definition of runlibfile. +/runlibfile /.runlibfile load def +currentdict /.runlibfile .undef + +% Bind all the operators defined as procedures. +/.bindoperators % binds operators in currentdict + { % Temporarily disable the typecheck error. + errordict /typecheck 2 copy get + errordict /typecheck { pop } put % pop the command + currentdict + { dup type /operatortype eq + { % This might be a real operator, so bind might cause a typecheck, + % but we've made the error a no-op temporarily. + .bind % do a real bind even if NOBIND is set + } + if pop pop + } forall + put + } def +NOBIND DELAYBIND or not { .bindoperators } if + +% Establish a default environment. + +defaultdevice +DISPLAYING not { setdevice (%END DISPLAYING) .skipeof } if +systemdict /DEVICEWIDTH known +systemdict /DEVICEHEIGHT known or +systemdict /DEVICEWIDTHPOINTS known or +systemdict /DEVICEHEIGHTPOINTS known or +systemdict /DEVICEXRESOLUTION known or +systemdict /DEVICEYRESOLUTION known or +systemdict /PAPERSIZE known or +not { (%END DEVICE) .skipeof } if +% Let DEVICE{WIDTH,HEIGHT}[POINTS] override PAPERSIZE. +systemdict /PAPERSIZE known +systemdict /DEVICEWIDTH known not and +systemdict /DEVICEHEIGHT known not and +systemdict /DEVICEWIDTHPOINTS known not and +systemdict /DEVICEHEIGHTPOINTS known not and + { % Convert the paper size to device dimensions. + true statusdict /.pagetypenames get + { PAPERSIZE eq + { PAPERSIZE load + dup 0 get /DEVICEWIDTHPOINTS exch def + 1 get /DEVICEHEIGHTPOINTS exch def + pop false exit + } + if + } + forall + { (Unknown paper size: ) print PAPERSIZE ==only (.\n) print + } + if + } +if +% Adjust the device parameters per the command line. +% It is possible to specify resolution, pixel size, and page size; +% since any two of these determine the third, conflicts are possible. +% We simply pass them to .setdeviceparams and let it sort things out. + mark /HWResolution null /HWSize null /PageSize null .dicttomark + .getdeviceparams .dicttomark begin + mark + % Check for resolution. + /DEVICEXRESOLUTION where dup + { exch pop HWResolution 0 DEVICEXRESOLUTION put } + if + /DEVICEYRESOLUTION where dup + { exch pop HWResolution 1 DEVICEYRESOLUTION put } + if + or { /HWResolution HWResolution } if + % Check for device sizes specified in pixels. + /DEVICEWIDTH where dup + { exch pop HWSize 0 DEVICEWIDTH put } + if + /DEVICEHEIGHT where dup + { exch pop HWSize 1 DEVICEHEIGHT put } + if + or { /HWSize HWSize } if + % Check for device sizes specified in points. + /DEVICEWIDTHPOINTS where dup + { exch pop PageSize 0 DEVICEWIDTHPOINTS put } + if + /DEVICEHEIGHTPOINTS where dup + { exch pop PageSize 1 DEVICEHEIGHTPOINTS put } + if + or { /PageSize PageSize } if + % Check whether any parameters were set. + dup mark eq { pop } { defaultdevice putdeviceprops } ifelse + end +%END DEVICE +% Set any device properties defined on the command line. +% If BufferSpace is defined but not MaxBitmap, set MaxBitmap to BufferSpace. +systemdict /BufferSpace known +systemdict /MaxBitmap known not and + { systemdict /MaxBitmap BufferSpace put + } if +dup getdeviceprops +counttomark 2 idiv + { systemdict 2 index known + { pop dup load counttomark 2 roll } + { pop pop } + ifelse + } repeat +counttomark dup 0 ne + { 2 add -1 roll putdeviceprops } + { pop pop } +ifelse +setdevice % does an erasepage +% If the media size is fixed, update the current page device dictionary. +FIXEDMEDIA +dup { pop systemdict /.currentpagedevice known } if +dup { pop .currentpagedevice exch pop } if +not { (%END MEDIA) .skipeof } if +currentpagedevice dup length dict .copydict +dup /InputAttributes +2 copy get dup length dict .copydict + % Stack: /InputAttributes +dup length dict .copydict dup +0 2 copy get dup length dict .copydict + % Stack: /InputAttributes + % 0 +dup /PageSize 7 index /PageSize get +put % PageSize in 0 +put % 0 in InputAttributes +put % InputAttributes in pagedevice +.setpagedevice +%END MEDIA +%END DISPLAYING + +(END DEVICE) VMDEBUG + +% Establish a default upper limit in the character cache, +% namely, enough room for a 18-point character at the resolution +% of the default device, or for a character consuming 1% of the +% maximum cache size, whichever is larger. +mark + % Compute limit based on character size. + 18 dup dtransform + exch abs cvi 31 add 32 idiv 4 mul % X raster + exch abs cvi mul % Y + % Compute limit based on allocated space. + cachestatus pop pop pop pop pop exch pop 0.01 mul cvi + .max dup 10 idiv exch +setcacheparams +% Conditionally disable the character cache. +NOCACHE { 0 setcachelimit } if + +(END CONFIG) VMDEBUG + +% Set the default screen based on the device resolution. +/.setdefaultscreen +{ + << + /HalftoneType 3 + /Width 16 + /Height 16 + /Thresholds + < 00 80 20 A0 08 88 28 A8 02 82 22 A2 0A 8A 2A AA + C0 40 E0 60 C8 48 E8 68 C2 42 E2 62 CA 4A EA 6A + 30 B0 10 90 38 B8 18 98 32 B2 12 92 3A BA 1A 9A + F0 70 D0 50 F8 78 D8 58 F2 72 D2 52 FA 7A DA 5A + 0C 8C 2C AC 04 84 24 A4 0E 8E 2E AE 06 86 26 A6 + CC 4C EC 6C C4 44 E4 64 CE 4E EE 6E C6 46 E6 66 + 3C BC 1C 9C 34 B4 14 94 3E BE 1E 9E 36 B6 16 96 + FC 7C DC 5C F4 74 D4 54 FE 7E DE 5E F6 76 D6 56 + 03 83 23 A3 0B 8B 2B AB 01 81 21 A1 09 89 29 A9 + C3 43 E3 63 CB 4B EB 6B C1 41 E1 61 C9 49 E9 69 + 33 B3 13 93 3B BB 1B 9B 31 B1 11 91 39 B9 19 99 + F3 73 D3 53 FB 7B DB 5B F1 71 D1 51 F9 79 D9 59 + 0F 8F 2F AF 07 87 27 A7 0D 8D 2D AD 05 85 25 A5 + CF 4F EF 6F C7 47 E7 67 CD 4D ED 6D C5 45 E5 65 + 3F BF 1F 9F 37 B7 17 97 3D BD 1D 9D 35 B5 15 95 + FF 7F DF 5F F7 77 D7 57 FD 7D DD 5D F5 75 D5 55 > + >> sethalftone +} bind def +.setdefaultscreen +% Set a null transfer function... +{} bind settransfer +initgraphics +% The interpreter relies on there being at least 2 entries +% on the graphics stack. Establish the second one now. +gsave + +% Define some control sequences as no-ops. +% This is a hack to get around problems +% in some common PostScript-generating applications. +% Note that <04> and <1a> are self-delimiting characters, like [. +<04> cvn { } def % Apple job separator +%<0404> cvn { } def % two of the same +<1b> cvn { } def % MS Windows LaserJet 4 prologue +%<041b> cvn { } def % MS Windows LaserJet 4 epilogue +(\001M) cvn % TBCP initiator + { currentfile /TBCPDecode filter cvx exec + } bind def +/@PJL % H-P job control + { currentfile //=string readline { pop } if + } bind def + +% If we want a "safer" system, disable some obvious ways to cause havoc. +SAFER not { (%END SAFER) .skipeof } if +/file + { dup (r) eq 2 index (%pipe*) .stringmatch not and + { file } + { /invalidfileaccess signalerror } + ifelse + } .bind odef +/renamefile { /invalidfileaccess signalerror } odef +/deletefile { /invalidfileaccess signalerror } odef +/putdeviceprops + { counttomark + dup 2 mod 0 eq { pop /rangecheck signalerror } if + 3 2 3 2 roll + { dup index /OutputFile eq + { -2 roll + dup () ne { /putdeviceprops load /invalidfileaccess signalerror } if + 3 -1 roll + } + { pop + } + ifelse + } for + putdeviceprops + } .bind odef + +%END SAFER + +% If we delayed binding, make it possible to do it later. +/.bindnow + { //systemdict begin .bindoperators end + % Temporarily disable the typecheck error. + errordict /typecheck 2 copy get + errordict /typecheck { pop } put % pop the command + 0 1 .delaycount 1 sub { .delaybind exch get .bind pop } for + userdict /.delaybind .undef % reclaim the space + userdict /.delaycount .undef + put + } .bind def + +% Turn off array packing, since some PostScript code assumes that +% procedures are writable. +false setpacking + +% Close up systemdict. +currentdict /.forceput .undef % remove temptation +currentdict /filterdict .undef % bound in where needed +end +WRITESYSTEMDICT not { systemdict readonly pop } if + +(END INIT) VMDEBUG + +% Establish local VM as the default. +false /setglobal where { pop setglobal } { .setglobal } ifelse +$error /.nosetlocal false put + +% Clean up VM, and enable GC. +/vmreclaim where + { pop NOGC not { 2 vmreclaim 0 vmreclaim } if + } if + +(END GC) VMDEBUG + +% The interpreter will run the initial procedure (start). diff --git a/pstoraster/gs_iso_e.ps b/pstoraster/gs_iso_e.ps new file mode 100644 index 0000000000..9be8b8aab7 --- /dev/null +++ b/pstoraster/gs_iso_e.ps @@ -0,0 +1,72 @@ +% Copyright (C) 1993, 1994 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Define the ISO Latin-1 encoding vector. +% The first half is the same as the standard encoding, +% except for minus instead of hyphen at code 055. +/ISOLatin1Encoding +StandardEncoding 0 45 getinterval aload pop + /minus +StandardEncoding 46 82 getinterval aload pop +% NOTE: the following are missing in the Adobe documentation, +% but appear in the displayed table: +% macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240. +% This is an error in the Red Book, corrected in Adobe TN 5085. +% \20x + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent + /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron +% \24x + /space /exclamdown /cent /sterling + /currency /yen /brokenbar /section + /dieresis /copyright /ordfeminine /guillemotleft + /logicalnot /minus /registered /macron + /degree /plusminus /twosuperior /threesuperior + /acute /mu /paragraph /periodcentered + /cedilla /onesuperior /ordmasculine /guillemotright + /onequarter /onehalf /threequarters /questiondown +% \30x + /Agrave /Aacute /Acircumflex /Atilde + /Adieresis /Aring /AE /Ccedilla + /Egrave /Eacute /Ecircumflex /Edieresis + /Igrave /Iacute /Icircumflex /Idieresis + /Eth /Ntilde /Ograve /Oacute + /Ocircumflex /Otilde /Odieresis /multiply + /Oslash /Ugrave /Uacute /Ucircumflex + /Udieresis /Yacute /Thorn /germandbls +% \34x + /agrave /aacute /acircumflex /atilde + /adieresis /aring /ae /ccedilla + /egrave /eacute /ecircumflex /edieresis + /igrave /iacute /icircumflex /idieresis + /eth /ntilde /ograve /oacute + /ocircumflex /otilde /odieresis /divide + /oslash /ugrave /uacute /ucircumflex + /udieresis /yacute /thorn /ydieresis +% Make an array on large systems, a packed array on small ones. +256 +vmstatus exch pop exch pop +100000 ge { array astore readonly } { packedarray } ifelse +def +1 ISOLatin1Encoding .registerencoding +/ISOLatin1Encoding ISOLatin1Encoding .defineencoding diff --git a/pstoraster/gs_kanji.ps b/pstoraster/gs_kanji.ps new file mode 100644 index 0000000000..c45dddfb9d --- /dev/null +++ b/pstoraster/gs_kanji.ps @@ -0,0 +1,164 @@ +% Copyright (C) 1994, 1995, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Scaffolding for Kanji fonts. This is based on the Wadalab free font +% from the University of Tokyo; it may not be appropriate for other +% Kanji fonts. + +/currentglobal where + { pop currentglobal { setglobal } true setglobal } + { { } } +ifelse + +% Define the encoding for the root font. + +/KanjiEncoding +% \x00 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 +% \x20 + 0 1 2 3 4 5 6 7 + 8 0 0 0 0 0 0 0 + 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 +% \x40 + 25 26 27 28 29 30 31 32 + 33 34 35 36 37 38 39 40 + 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 +% \x60 + 57 58 59 60 61 62 63 64 + 65 66 67 68 69 70 71 72 + 73 74 75 76 77 0 0 0 + 0 0 0 0 0 0 0 0 +% \x80 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 +% \xA0 + 0 1 2 3 4 5 6 7 + 8 0 0 0 0 0 0 0 + 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 +% \xC0 + 25 26 27 28 29 30 31 32 + 33 34 35 36 37 38 39 40 + 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 +% \xE0 + 57 58 59 60 61 62 63 64 + 65 66 67 68 69 70 71 72 + 73 74 75 76 77 0 0 0 + 0 0 0 0 0 0 0 0 +256 packedarray def + +% Define a stub for the base font encoding. + + /KanjiSubEncoding { /KanjiSubEncoding .findencoding } bind def +%% Replace 3 (gs_ksb_e.ps) + EncodingDirectory /KanjiSubEncoding + { (gs_ksb_e.ps) //systemdict begin runlibfile KanjiSubEncoding end } + bind put + +% Support procedures and data. + +/T1FontInfo 8 dict begin + /version (001.001) readonly def + /FullName (KanjiBase) readonly def + /FamilyName (KanjiBase) readonly def + /Weight (Medium) readonly def + /ItalicAngle 0 def + /isFixedPitch false def + /UnderlinePosition 0 def + /UnderlineThickness 0 def +currentdict end readonly def + +/T1NF % T1NF +{ +20 dict begin + /FontName exch def + /FontType 1 def + /FontInfo T1FontInfo def + /FontMatrix [.001 0 0 .001 0 0] def + /FontBBox [0 0 1000 1000] def + /Encoding KanjiSubEncoding def + /CharStrings 150 dict def + /PaintType 0 def + /Private 2 dict def + Private begin + /BlueValues [] def + /password 5839 def + end +FontName currentdict end definefont +} def + +/T0NF % T0NF +{ +20 dict begin + /FontName exch def + /FDepVector exch def + /FontType 0 def + /FontMatrix [1 0 0 1 0 0] def + /FMapType 2 def + /Encoding KanjiEncoding def +FontName currentdict end definefont +} def + +% Define the composite font and all the base fonts. + +/CompNF % CompNF +{ +/newname1 exch def +newname1 dup length string cvs /str exch def +str length /len exch def +/fdepvector 78 array def +/j 1 def +16#21 1 16#74 { +/i exch def +KanjiEncoding i get 0 gt { +len 4 add string /newstr exch def +newstr 0 str putinterval +newstr len (.r) putinterval +newstr len 2 add i 16 2 string cvrs putinterval +newstr cvn /newlit exch def +newlit T1NF /newfont exch def +fdepvector j newfont put +/j j 1 add def +} if +} for +fdepvector 0 fdepvector 1 get put +/j 0 def +fdepvector newname1 T0NF +} def + +% Define an individual character in a composite font. +/CompD % <(HL)> CompD - + { currentfont /Encoding get 1 index 0 get get % FDepVector index + currentfont /FDepVector get exch get % base font + dup /Encoding get 3 -1 roll 1 get get % base font character name + exch /CharStrings get exch 3 -1 roll put + } bind def + +exec diff --git a/pstoraster/gs_ksb_e.ps b/pstoraster/gs_ksb_e.ps new file mode 100644 index 0000000000..765a05e3bc --- /dev/null +++ b/pstoraster/gs_ksb_e.ps @@ -0,0 +1,70 @@ +% Copyright (C) 1994 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Define the KanjiSub encoding vector. +/currentglobal where + { pop currentglobal { setglobal } true setglobal } + { { } } +ifelse +/KanjiSubEncoding +%\x00 + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +%\x20 + /.notdef /c21 /c22 /c23 /c24 /c25 /c26 /c27 + /c28 /c29 /c2A /c2B /c2C /c2D /c2E /c2F + /c30 /c31 /c32 /c33 /c34 /c35 /c36 /c37 + /c38 /c39 /c3A /c3B /c3C /c3D /c3E /c3F +%\x40 + /c40 /c41 /c42 /c43 /c44 /c45 /c46 /c47 + /c48 /c49 /c4A /c4B /c4C /c4D /c4E /c4F + /c50 /c51 /c52 /c53 /c54 /c55 /c56 /c57 + /c58 /c59 /c5A /c5B /c5C /c5D /c5E /c5F +%\x60 + /c60 /c61 /c62 /c63 /c64 /c65 /c66 /c67 + /c68 /c69 /c6A /c6B /c6C /c6D /c6E /c6F + /c70 /c71 /c72 /c73 /c74 /c75 /c76 /c77 + /c78 /c79 /c7A /c7B /c7C /c7D /c7E /.notdef +%\x80 + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +%\xA0 + /.notdef /c21 /c22 /c23 /c24 /c25 /c26 /c27 + /c28 /c29 /c2A /c2B /c2C /c2D /c2E /c2F + /c30 /c31 /c32 /c33 /c34 /c35 /c36 /c37 + /c38 /c39 /c3A /c3B /c3C /c3D /c3E /c3F +%\xC0 + /c40 /c41 /c42 /c43 /c44 /c45 /c46 /c47 + /c48 /c49 /c4A /c4B /c4C /c4D /c4E /c4F + /c50 /c51 /c52 /c53 /c54 /c55 /c56 /c57 + /c58 /c59 /c5A /c5B /c5C /c5D /c5E /c5F +%\xE0 + /c60 /c61 /c62 /c63 /c64 /c65 /c66 /c67 + /c68 /c69 /c6A /c6B /c6C /c6D /c6E /c6F + /c70 /c71 /c72 /c73 /c74 /c75 /c76 /c77 + /c78 /c79 /c7A /c7B /c7C /c7D /c7E /.notdef +256 packedarray .defineencoding +exec diff --git a/pstoraster/gs_l2img.ps b/pstoraster/gs_l2img.ps new file mode 100644 index 0000000000..2a24c3cb02 --- /dev/null +++ b/pstoraster/gs_l2img.ps @@ -0,0 +1,191 @@ +% Copyright (C) 1995, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Emulate the Level 2 dictionary-based image operator in Level 1, +% except for Interpolate (ignored) and MultipleDataSources = true; +% also, we require that the data source be either a procedure of a +% particular form or a stream, not a string or a general procedure. + +% pdf2ps copies the portion of this file from %BEGIN to %END if Level 1 +% compatible output is requested. + +/currentglobal where + { pop currentglobal { setglobal } true setglobal } + { { } } +ifelse + +/packedarray where + { pop } + { /packedarray { array astore readonly } bind def } +ifelse + +%BEGIN + +11 dict /.csncompdict 1 index def begin + /DeviceGray { 1 /setgray load } bind def + /DeviceRGB { 3 /setrgbcolor load } bind def + /DeviceCMYK { 4 /setcmykcolor load } bind def + /Indexed + { dup 1 index 1 get //.csncompdict exch get exec + % Stack: [/Indexed base hival map] ncomp basesetcolor + 3 -1 roll 3 get mark 3 1 roll + % Stack: ncomp -mark- basesetcolor map + dup type /stringtype eq + { { - + { exch round cvi get 255 div + } + - + { exch round cvi 3 mul 2 copy 2 copy get 255 div + 3 1 roll 1 add get 255 div + 4 2 roll 2 add get 255 div + } + { exch round cvi 4 mul 2 copy 2 copy 2 copy get 255 div + 3 1 roll 1 add get 255 div + 4 2 roll 2 add get 255 div + 5 3 roll 3 add get 255 div + } + } + 4 index get aload pop counttomark -1 roll + } + { /exec load 3 -1 roll + % Stack: -mark- mapproc --exec-- basesetcolor + } + ifelse .packtomark cvx + exch pop 1 exch + } bind def + /Separation + { dup 2 index //.csncompdict exch get exec + % Stack: [/Separation name alt xform] ncomp altsetcolor + 3 -1 roll 3 get /exec load 3 -1 roll 3 array astore readonly cvx + exch pop 1 exch + } bind def + % Substitute device spaces for CIE spaces. + /CIEBasedA /DeviceGray load def + /CIEBasedABC /DeviceRGB load def + /CIEBasedDEF /DeviceRGB load def + /CIEBasedDEFG /DeviceCMYK load def +end + +/.packtomark { counttomark packedarray exch pop } bind def + +/.csinextbits % - .csinextbits + % Uses b, nnb, i, row, mask, BitsPerComponent; + % sets b, nnb, i. + { /nnb nnb BitsPerComponent add + { dup 0 le { exit } if + /b b 8 bitshift row i get add def + /i i 1 add def 8 sub + } + loop def + b nnb bitshift mask and + } bind def + +% Note that the ColorSpace key must be present in the image dictionary. +/.colorspaceimage % .colorspaceimage - + { save exch + dup length 15 add dict begin { cvlit def } forall + ColorSpace dup dup type /nametype ne { 0 get } if + .csncompdict exch get exec + /setpixelcolor exch def /ncomp exch def pop + /row ncomp BitsPerComponent mul Width mul 7 add 8 idiv string def + /mask 1 BitsPerComponent bitshift 1 sub def + /nextbits BitsPerComponent 8 eq + { { row i get /i i 1 add def } } + { /.csinextbits load } + ifelse def + /nextpixel mark 0 2 ncomp 1 sub 2 mul + { /nextbits cvx exch + Decode exch 2 getinterval + dup aload pop exch sub + dup mask eq { pop } { mask div /mul load 3 -1 roll } ifelse + 0 get dup 0 eq { pop } { /sub load 3 -1 roll } ifelse + } + for + /setpixelcolor load dup type /operatortype ne { /exec load } if + .packtomark cvx def + /readrow + /DataSource load dup type + dup /arraytype eq exch /packedarraytype eq or + { % Must be { ... } + aload length 1 add array /pop load exch astore + dup 1 row put cvx + } + { pop + % Adobe requires readstring to signal an error if given + % an empty string. Work around this nonsense here. + row length 0 eq + { { } } + { { DataSource row readstring pop pop } } + ifelse + } + ifelse def + ImageMatrix matrix invertmatrix concat + /imat matrix def + 0 1 Height 1 sub + { imat 5 3 -1 roll neg put +%(.) print flush + readrow + /b 0 def /nnb 0 def /i 0 def + 0 1 Width 1 sub + { imat 4 3 -1 roll neg put nextpixel + 1 1 true imat {<80>} imagemask + } + for + } + for + end restore + } bind def + +%END +exec +currentfile closefile + +% Patch for testing. +/.cincompdict 3 dict begin + 1 { {0 1} {/DeviceGray} } def + 3 { {0 1 0 1 0 1} {/DeviceRGB} } def + 4 { {0 1 0 1 0 1 0 1} {/DeviceCMYK} } def +currentdict end def +/.imagekeys [ + /Decode /DataSource /ImageMatrix /BitsPerComponent /Height /Width +] def +/colorimage % + % false colorimage - + { 1 index { /colorimage load /rangecheck signalerror } if exch pop + //.cincompdict exch get exec + 7 dict begin /ColorSpace exch cvlit def + .imagekeys { exch cvlit def } forall + currentdict end .colorspaceimage + } bind odef +/image + { dup type /dicttype ne + { 7 dict begin /ColorSpace /DeviceGray def [0 1] + .imagekeys { exch cvlit def } forall + currentdict end + } + { dup length 1 add dict .copydict dup /ColorSpace currentcolorspace put + } + ifelse + .colorspaceimage + } bind odef + +exec diff --git a/pstoraster/gs_lev2.ps b/pstoraster/gs_lev2.ps new file mode 100644 index 0000000000..125872f1ff --- /dev/null +++ b/pstoraster/gs_lev2.ps @@ -0,0 +1,332 @@ +% Copyright (C) 1990, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Initialization file for Level 2 functions. +% When this is run, systemdict is still writable, +% but (almost) everything defined here goes into level2dict. + +level2dict begin + +% ------ Miscellaneous ------ % + +(<<) cvn /mark load def +(>>) cvn /.dicttomark load def +/currentsystemparams { mark .currentsystemparams .dicttomark } odef +/currentuserparams { mark .currentuserparams .dicttomark } odef +/deviceinfo { currentdevice getdeviceprops .dicttomark readonly } odef +/languagelevel 2 def +% When running in Level 2 mode, this interpreter is supposed to be +% compatible with PostScript version 2017 (I think). +/version (2017) def + +% If binary tokens are supported by this interpreter, +% set an appropriate default binary object format. +/setobjectformat where + { pop + currentsystemparams dup + /RealFormat get (IEEE) eq { 1 } { 3 } ifelse + exch /ByteOrder get { 1 add } if + setobjectformat + } if + +% ------ Virtual memory ------ % + +/currentglobal /currentshared load def +/gcheck /scheck load def +/setglobal /setshared load def +% We can make the global dictionaries very small, because they auto-expand. +/globaldict currentdict /shareddict .knownget not { 4 dict } if def +/GlobalFontDirectory SharedFontDirectory def + +% ------ IODevices ------ % + +/.getdevparams where + { pop /currentdevparams { .getdevparams .dicttomark } odef + } if +/.putdevparams where + { pop /setdevparams { mark exch { } forall counttomark 2 add -1 roll .putdevparams } odef + } if + +% ------ Job control ------ % + +serverdict begin + +% We could protect the job information better, but we aren't attempting +% (currently) to protect ourselves against maliciousness. + +/.jobsave null def % top-level save object +/.jobsavelevel 0 def % save depth of job (0 if .jobsave is null, + % 1 otherwise) +/.adminjob true def % status of current unencapsulated job + +/exitserver + { true exch startjob not { /exitserver /invalidaccess signalerror } if + } bind def + +end % serverdict + +%**************** The definition of startjob is not complete yet, since +% it doesn't clear the exec stack, doesn't reset stdin/stdout, +% doesn't run the job under its own control, and doesn't reset +% other aspects of the interpreter. +/startjob + { vmstatus pop pop serverdict /.jobsavelevel get eq + 1 index .checkpassword 0 gt and + { .checkpassword count 2 roll count 2 sub { pop } repeat + cleardictstack + serverdict /.jobsave get dup null eq { pop } { restore } ifelse + exch + { % unencapsulated job + serverdict /.jobsave null put + serverdict /.jobsavelevel 0 put + serverdict /.adminjob 3 -1 roll 1 gt put + } + { % encapsulated job + serverdict /.jobsave save put + serverdict /.jobsavelevel 1 put + userdict /quit /stop load put + pop + } + ifelse true + } + { pop pop false + } + ifelse + } odef + +systemdict begin +/quit + { //systemdict /serverdict get /.jobsave get null eq + { //quit } + { //systemdict /quit get /invalidaccess signalerror } + ifelse + } bind odef +end + +% ------ Compatibility ------ % + +% In Level 2 mode, the following replace the definitions that gs_statd.ps +% installs in statusdict and serverdict. +% Note that statusdict must be allocated in local VM. +% We don't bother with many of these yet, and the ones defined in terms +% of currentsystemparams are cavalier about allocating a dictionary +% in order to retrieve a single element from it.... + +/.dict1 { exch mark 3 1 roll .dicttomark } bind def + +currentglobal false setglobal 25 dict exch setglobal begin +currentsystemparams + +/buildtime 1 index /BuildTime get def +/byteorder 1 index /ByteOrder get def +/checkpassword { .checkpassword 0 gt } bind def +/defaulttimeouts + { currentsystemparams dup + /JobTimeout .knownget not { 0 } if + exch /WaitTimeout .knownget not { 0 } if + currentpagedevice /ManualFeedTimeout .knownget not { 0 } if + } bind def +dup /DoStartPage known + { /dostartpage { currentsystemparams /DoStartPage get } bind def + /setdostartpage { /DoStartPage .dict1 setsystemparams } bind def + } if +dup /StartupMode known + { /dosysstart { currentsystemparams /StartupMode get 0 ne } bind def + /setdosysstart { { 1 } { 0 } ifelse /StartupMode .dict1 setsystemparams } bind def + } if +%****** Setting jobname is supposed to set userparams.JobName, too. +/jobname { currentuserparams /JobName get } bind def +/jobtimeout { currentuserparams /JobTimeout get } bind def +%manualfeed +%manualfeedtimeout +/margins + { currentpagedevice /Margins .knownget { exch } { [0 0] } ifelse + } bind def +%pagecount +%pagestackorder +/printername + { currentsystemparams /PrinterName .knownget not { () } if exch copy + } bind def +%/ramsize { currentsystemparams /RamSize get } bind def +/realformat 1 index /RealFormat get def + +/.setpagedevice where + { pop + /setdefaulttimeouts + { exch mark /ManualFeedTimeout 3 -1 roll + /Policies mark /ManualFeedTimeout 1 .dicttomark + .dicttomark setpagedevice + /WaitTimeout exch mark /JobTimeout 5 2 roll .dicttomark setsystemparams + } bind def + /setmargins + { exch 2 array astore /Margins .dict1 setpagedevice + } bind def + } +if +%setpagestackorder +dup /PrinterName known + { /setprintername { /PrinterName .dict1 setsystemparams } bind def + } if +currentuserparams /WaitTimeout known + { /waittimeout { currentuserparams /WaitTimeout get } bind def + } if + +/.setpagedevice where + { pop + /pagemargin + { currentpagedevice /PageOffset .knownget { 0 get } { 0 } ifelse + } bind def + /pageparams + { currentpagedevice + dup /Orientation .knownget { 1 and ORIENT1 { 1 xor } if } { 0 } ifelse exch + dup /PageSize get aload pop 3 index 0 ne { exch } if 3 2 roll + /PageOffset .knownget { 0 get } { 0 } ifelse 4 -1 roll + } bind def + /.setpagesize { 2 array astore /PageSize .dict1 setpagedevice } bind def + /setduplexmode { /Duplex .dict1 setpagedevice } bind def + /setpagemargin { 0 2 array astore /PageOffset .dict1 setpagedevice } bind def + /setpageparams + { mark /PageSize 6 -2 roll + 4 index 1 and ORIENT1 { 1 } { 0 } ifelse ne { exch } if 2 array astore + /Orientation 5 -1 roll ORIENT1 { 1 xor } if + /PageOffset counttomark 2 add -1 roll 0 2 array astore + .dicttomark setpagedevice + } bind def + /setresolution + { dup 2 array astore /HWResolution .dict1 setpagedevice + } bind def + } +if + +pop % currentsystemparams + +% Flag the current dictionary so it will be swapped when we +% change language levels. (See zmisc2.c for more information.) +/statusdict currentdict def + +currentdict end +/statusdict exch def + +% ------ Color spaces ------ % + +% Define the setcolorspace procedures. +/colorspacedict mark + /DeviceGray { pop 0 setgray } bind + /DeviceRGB { pop 0 0 0 setrgbcolor } bind + /setcmykcolor where + { pop /DeviceCMYK { pop 0 0 0 1 setcmykcolor } bind + } if + /.setcieaspace where + { pop /CIEBasedA { NOCIE { pop 0 setgray } { 1 get .setcieaspace } ifelse } bind + } if + /.setcieabcspace where + { pop /CIEBasedABC { NOCIE { pop 0 0 0 setrgbcolor } { 1 get .setcieabcspace } ifelse } bind + } if + /.setciedefspace where + { pop /CIEBasedDEF { NOCIE { pop 0 0 0 setrgbcolor } { 1 get .setciedefspace } ifelse } bind + } if + /.setciedefgspace where + { pop /CIEBasedDEFG { NOCIE { pop 0 0 0 1 setcmykcolor } { 1 get .setciedefgspace } ifelse } bind + } if + /.setseparationspace where + { pop /Separation { dup 2 get setcolorspace .setseparationspace } bind + } if + /.setindexedspace where + { pop /Indexed { dup 1 get setcolorspace .setindexedspace } bind + } if + /.setpatternspace where + { pop /Pattern + { dup length 1 gt { dup 1 get setcolorspace } if + .setpatternspace + } bind + } if +.dicttomark def + +/.devcs [/DeviceGray /DeviceRGB /DeviceCMYK] readonly def +/currentcolorspace + { .currentcolorspace dup type /integertype eq + { //.devcs exch 1 getinterval + } if + } odef +currentdict /.devcs .undef + +/setcolorspace + { dup type /nametype eq { 1 array astore } if + dup //colorspacedict 1 index 0 get get exec + .setcolorspace + } odef + +% Initialize the CIE rendering dictionary if necessary. +% The most common CIE files seem to assume the "calibrated RGB color space" +% described on p. 189 of the PostScript Language Reference Manual, +% 2nd Edition; we simply invert this transformation back to RGB. +/setcolorrendering where + { pop mark + /ColorRenderingType 1 +% We must make RangePQR and RangeLMN large enough so that values computed by +% the assumed encoding MatrixLMN don't get clamped. + /RangePQR [0 0.9505 0 1 0 1.0890] + /TransformPQR [ { } dup dup ] + /RangeLMN [0 0.9505 0 1 0 1.0890] + /MatrixABC + [ 3.24063 -0.96893 0.05571 + -1.53721 1.87576 -0.20402 + -0.49863 0.04152 1.05700 + ] + /EncodeABC [{0 max 0.45 exp} bind dup dup] + /WhitePoint [0.9505 1 1.0890] + .dicttomark setcolorrendering + } if + +% ------ Painting ------ % + +% A straightforward definition of execform that doesn't actually +% do any caching. +/execform + { dup /Implementation known not + { dup /FormType get 1 ne { /rangecheck signalerror } if + dup /Implementation null put readonly + } if + gsave dup /Matrix get concat + dup /BBox get aload pop + exch 3 index sub exch 2 index sub rectclip + dup /PaintProc get exec + grestore + } odef + +/makepattern + { currentglobal + { false setglobal .buildpattern true setglobal } + { .buildpattern } + ifelse + exch dup length 1 add dict .copydict + dup /Implementation 4 -1 roll put + readonly + } odef + +/setpattern + { currentcolorspace 0 get /Pattern ne + { [ /Pattern currentcolorspace ] setcolorspace } if + setcolor + } odef + +end % level2dict diff --git a/pstoraster/gs_mex_e.ps b/pstoraster/gs_mex_e.ps new file mode 100644 index 0000000000..fb4ba6936e --- /dev/null +++ b/pstoraster/gs_mex_e.ps @@ -0,0 +1,70 @@ +% Copyright (C) 1994 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Define the MacExpert encoding vector. +/currentglobal where + { pop currentglobal { setglobal } true setglobal } + { { } } +ifelse +/MacExpertEncoding +% \00x + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef +% \04x + /space /exclamsmall /Hungarumlautsmall /centoldstyle /dollaroldstyle /dollarsuperior /ampersandsmall /Acutesmall + /parenleftsuperior /parenrightsuperior /twodotenleader /onedotenleader /comma /hyphen /period /fraction + /zerooldstyle /oneoldstyle /twooldstyle /threeoldstyle /fouroldstyle /fiveoldstyle /sixoldstyle /sevenoldstyle + /eightoldstyle /nineoldstyle /colon /semicolon /.notdef /threequartersemdash /.notdef /questionsmall +% \10x + /.notdef /.notdef /.notdef /.notdef /Ethsmall /.notdef /.notdef /onequarter + /onehalf /threequarters /oneeighth /threeeighths /fiveeighths /seveneighths /onethird /twothirds + /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /ff /fi + /fl /ffi /ffl /parenleftinferior /.notdef /parenrightinferior /Circumflexsmall /hypheninferior +% \14x + /Gravesmall /Asmall /Bsmall /Csmall /Dsmall /Esmall /Fsmall /Gsmall + /Hsmall /Ismall /Jsmall /Ksmall /Lsmall /Msmall /Nsmall /Osmall + /Psmall /Qsmall /Rsmall /Ssmall /Tsmall /Usmall /Vsmall /Wsmall + /Xsmall /Ysmall /Zsmall /colonmonetary /onefitted /rupiah /Tildesmall /.notdef +% \20x + /.notdef /asuperior /centsuperior /.notdef /.notdef /.notdef /.notdef /Aacutesmall + /Agravesmall /Acircumflexsmall /Adieresissmall /Atildesmall /Aringsmall /Ccedillasmall /Eacutesmall /Egravesmall + /Ecircumflexsmall /Edieresissmall /Iacutesmall /Igravesmall /Icircumflexsmall /Idieresissmall /Ntildesmall /Oacutesmall + /Ogravesmall /Ocircumflexsmall /Odieresissmall /Otildesmall /Uacutesmall /Ugravesmall /Ucircumflexsmall /Udieresissmall +% \24x + /.notdef /eightsuperior /fourinferior /threeinferior /sixinferior /eightinferior /seveninferior /Scaronsmall + /.notdef /centinferior /twoinferior /.notdef /Dieresissmall /.notdef /Caronsmall /osuperior + /fiveinferior /.notdef /commainferior /periodinferior /Yacutesmall /.notdef /dollarinferior /.notdef + /.notdef /Thornsmall /.notdef /nineinferior /zeroinferior /Zcaronsmall /AEsmall /Oslashsmall +% \30x + /questiondownsmall /oneinferior /Lslashsmall /.notdef /.notdef /.notdef /.notdef /.notdef + /.notdef /Cedillasmall /.notdef /.notdef /.notdef /.notdef /.notdef /OEsmall + /figuredash /hyphensuperior /.notdef /.notdef /.notdef /.notdef /exclamdownsmall /.notdef + /Ydieresissmall /.notdef /onesuperior /twosuperior /threesuperior /foursuperior /fivesuperior /sixsuperior +% \34x + /sevensuperior /ninesuperior /zerosuperior /.notdef /esuperior /rsuperior /tsuperior /.notdef + /.notdef /isuperior /ssuperior /dsuperior /.notdef /.notdef /.notdef /.notdef + /.notdef /lsuperior /Ogoneksmall /Brevesmall /Macronsmall /bsuperior /nsuperior /msuperior + /commasuperior /periodsuperior /Dotaccentsmall /Ringsmall /.notdef /.notdef /.notdef /.notdef +256 packedarray .defineencoding +exec diff --git a/pstoraster/gs_mro_e.ps b/pstoraster/gs_mro_e.ps new file mode 100644 index 0000000000..f77cc74610 --- /dev/null +++ b/pstoraster/gs_mro_e.ps @@ -0,0 +1,63 @@ +% Copyright (C) 1994 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Define the MacRoman encoding vector. +/currentglobal where + { pop currentglobal { setglobal } true setglobal } + { { } } +ifelse +/MacRomanEncoding +StandardEncoding 0 39 getinterval aload pop + /quotesingle +StandardEncoding 40 56 getinterval aload pop + /grave +StandardEncoding 97 31 getinterval aload pop +% \20x + /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 +% \24x + /dagger /degree /cent /sterling /section /bullet /paragraph /germandbls + /registered /copyright /trademark /acute /dieresis /.notdef /AE /Oslash + /.notdef /plusminus /.notdef /.notdef /yen /mu /.notdef /.notdef + /.notdef /.notdef /.notdef /ordfeminine /ordmasculine /.notdef /ae /oslash +% \30x + /questiondown /exclamdown /logicalnot /.notdef + /florin /.notdef /.notdef /guillemotleft + /guillemotright /ellipsis /space /Agrave /Atilde /Otilde /OE /oe + /endash /emdash /quotedblleft /quotedblright + /quoteleft /quoteright /divide /.notdef + /ydieresis /Ydieresis /fraction /currency + /guilsingleft /guilsingright /fi /fl +% \34x + /daggerdbl /periodcentered /quotesinglbase /quotedblbase + /perthousand /Acircumflex /Ecircumflex /Aacute + /Edieresis /Egrave /Iacute /Icircumflex + /Idieresis /Igrave /Oacute /Ocircumflex + /.notdef /Ograve /Uacute /Ucircumflex + /Ugrave /dotlessi /circumflex /tilde + /macron /breve /dotaccent /ring /cedilla /hungarumlaut /ogonek /caron +256 packedarray .defineencoding +exec diff --git a/pstoraster/gs_pdf.ps b/pstoraster/gs_pdf.ps new file mode 100644 index 0000000000..2c4ce8df49 --- /dev/null +++ b/pstoraster/gs_pdf.ps @@ -0,0 +1,575 @@ +% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% gs_pdf.ps +% ProcSet for PostScript files created by the PDF to PostScript converter. +% This ProcSet requires only a Level 1 interpreter. + +% pdf2ps copies this file from %BEGIN to the end. + +%BEGIN +mark % patches +/currentglobal { false } +/setglobal { pop } +/packedarray { array astore readonly } +/setcmykcolor + { 1 exch sub + 4 -1 roll 1 exch sub 1 index mul + 4 -1 roll 1 exch sub 2 index mul + 4 -2 roll exch 1 exch sub mul + setrgbcolor + } +/.copydict + { dup 3 -1 roll { put dup } forall pop } +/.dicttomark + { counttomark 2 idiv dup dict begin { def } repeat pop currentdict end } +/.knownget + { 2 copy known { get true } { pop pop false } ifelse } +counttomark 2 idiv + { 1 index where { pop pop pop } { bind executeonly def } ifelse + } repeat pop + +currentglobal true setglobal + +% Define pdfmark. Don't allow it to be bound in. +% Also don't define it in systemdict, because this leads some Adobe code +% to think this interpreter is a distiller. +% (If this interpreter really is a distiller, don't do this.) +systemdict /pdfmark known not + { userdict /pdfmark { cleartomark } bind put } if + +% This ProcSet is designed so that it can be used either to execute PDF +% (the default) or to convert PDF to PostScript. See ! and ~ below. + +userdict /GS_PDF_ProcSet 119 dict dup begin + +% ---------------- Abbreviations ---------------- % + +/bdef { bind def } bind def + +% ---------------- Operator execution ---------------- % + +% We record "operator" names in a dictionary with their argument counts, +% so that they can easily be redefined later to write PostScript in +% addition to (or instead of) being executed. + +/numargsdict 100 dict def +/! % ! - + { //numargsdict 3 index 3 -1 roll put def + } bdef +/~ % ~ - + { exch cvx 1 packedarray cvx exch ! + } bdef + +% ---------------- Graphics state stack ---------------- % + +% PDF adds a number of parameters to the graphics state. +% We implement this by pushing and popping a dictionary +% each time we do a PDF gsave or grestore. +% The keys in this dictionary are as follows: +% self % identifies the dictionary as one of ours +% Show +% TextOrigin % origin of current line, in text space +% TextSaveMatrix % matrix at time of BT +% (The following correspond directly to PDF state parameters.) +% FillColor +% FillColorSpace +% StrokeColor +% StrokeColorSpace +% TextSpacing +% TextHScaling +% Leading +% TextFont +% TextMatrix +% TextRise +% TextRenderingMode +% WordSpacing + +/nodict 1 dict def +nodict /self { //nodict } executeonly put +nodict readonly pop + +/beginpage + { //nodict 20 dict .copydict begin graphicsbeginpage textbeginpage + } bdef +/endpage + { showpage end + } bdef + +/graphicsbeginpage { initgraphics 0 g 0 G } bdef + +/gput % gput - + { exch currentdict //nodict eq { /self dup load end 5 dict begin def } if + % If we're in a Level 1 system, we need to grow the + % dictionary explicitly. + currentdict length currentdict maxlength ge %eq + { currentdict dup length 3 mul 2 idiv 1 add dict .copydict end begin + } + if def + } bdef + +/q_ + { gsave //nodict begin + } bdef +/q /q_ load 0 ! +% Some PDF files have excess Q operators! +/Q_ + { currentdict /self .knownget { exec //nodict eq { end grestore } if } if + } bdef +/Q /Q_ load 0 ! + +% ---------------- Graphics state parameters ---------------- % + +/d /setdash 2 ~ +/i /setflat 1 ~ +/j /setlinejoin 1 ~ +/J /setlinecap 1 ~ +/M /setmiterlimit 1 ~ +/w /setlinewidth 1 ~ + +% ---------------- Color setting ---------------- % + +/fcput % fcput - + { /FillColorSpace gput /FillColor gput + } bdef +/scput % scput - + { /StrokeColorSpace gput /StrokeColor gput + } bdef + +/csdevgray [/DeviceGray] readonly def +/csdevrgb [/DeviceRGB] readonly def +/csdevcmyk [/DeviceCMYK] readonly def + +/CSdict 11 dict dup begin + /DeviceGray { 0 exch } bdef + /DeviceRGB { [0 0 0] cvx exch } bdef + /DeviceCMYK { [0 0 0 1] cvx exch } bdef + /Indexed + { dup 1 get csset exch pop + dup 2 index 1 get eq + { pop } + { exch 4 array copy dup 1 4 -1 roll put } + ifelse 0 exch + } bdef + /setcolorrendering where + { pop + /CalGray + { 1 get dup /Gamma .knownget + { dup length 1 add dict .copydict + dup /DecodeA 4 -1 roll /exp load 2 packedarray cvx put + } + if /CIEBasedA exch 2 array astore 0 exch + } bdef + /CalRGB + { 1 get dup /Gamma known 1 index /Matrix known or + { dup length 2 add dict .copydict + dup /Matrix .knownget { 1 index /MatrixABC 3 -1 roll put } if + dup /Gamma .knownget + { [ exch { /exp load 2 packedarray cvx } forall + ] 1 index /DecodeABC 3 -1 roll put + } + if + } + if /CIEBasedABC exch 2 array astore [0 0 0] cvx exch + } bdef + /CalCMYK { pop //csdevcmyk csset } bdef % not supported yet + } + { /CalGray { pop //csdevgray csset } bdef + /CalRGB { pop //csdevrgb csset } bdef + /CalCMYK { pop //csdevcmyk csset } bdef + } + ifelse +end def +/csset % csset + { dup dup type /nametype ne { 0 get } if //CSdict exch get exec + } bdef + +/g { //csdevgray fcput } 1 ! +/G { //csdevgray scput } 1 ! +/rg { 3 array astore cvx //csdevrgb fcput } 3 ! +/RG { 3 array astore cvx //csdevrgb scput } 3 ! +/k { 4 array astore cvx //csdevcmyk fcput } 4 ! +/K { 4 array astore cvx //csdevcmyk scput } 4 ! +/cs { csset fcput } 1 ! +/CS { csset scput } 1 ! +% We have to break up sc according to the number of operands. +/sc1 { /FillColor gput } 1 ! +/SC1 { /StrokeColor gput } 1 ! +/sc3 { /FillColor load astore pop } 3 ! +/SC3 { /StrokeColor load astore pop } 3 ! +/sc4 { /FillColor load astore pop } 4 ! +/SC4 { /StrokeColor load astore pop } 4 ! + +% ---------------- Color installation ---------------- % + +% Establish a given color (and color space) as current. +/setfillcolor { FillColor FillColorSpace setgcolor } def +/setstrokecolor { StrokeColor StrokeColorSpace setgcolor } def +/CIdict mark % only used for Level 1 + /DeviceGray 1 /DeviceRGB 3 /DeviceCMYK 4 + /CIEBaseA 1 /CIEBaseABC 3 /CIEBasedDEF 3 /CIEBaseDEFG 4 +.dicttomark def +/Cdict 11 dict dup begin % -proc- - + /DeviceGray { pop setgray } bdef + /DeviceRGB { pop setrgbcolor } bdef + /DeviceCMYK { pop setcmykcolor } bdef + /CIEBasedA + { dup currentcolorspace eq { pop } { setcolorspace } ifelse setcolor } bdef + /CIEBasedABC /CIEBasedA load def + /CIEBasedDEF /CIEBasedA load def + /CIEBasedDEFG /CIEBasedA load def + /Indexed /setcolorspace where + { pop /CIEBasedA load } + { /setindexedcolor cvx } + ifelse def +end def +/setindexedcolor % [/Indexed base hival proc|str] + % setindexedcolor - (only used for Level 1) + { mark 3 -1 roll + 2 index 3 get % Stack: cspace -mark- index proc|str + dup type /stringtype eq + { //CIdict 4 index 1 get 0 get get % # of components + dup 4 -1 roll mul exch getinterval { 255 div } forall + } + { exec + } + ifelse + counttomark 2 add -2 roll pop + 1 get setgcolor + } bdef +/setgcolor % (null | ) setgcolor - + { 1 index null eq + { pop pop } + { dup 0 get //Cdict exch get exec } + ifelse + } bdef +/fsexec % fsexec - + { % Preserve the current point, if any. + { currentpoint } stopped + { $error /newerror false put cvx exec } + { 3 -1 roll cvx exec moveto } + ifelse + } bdef + +% ---------------- Transformations ---------------- % + +/cmmatrix matrix def +/cm { //cmmatrix astore concat } 6 ! + +% ---------------- Path creation ---------------- % + +/m /moveto 2 ~ +/l /lineto 2 ~ +/c /curveto 6 ~ +/h /closepath 0 ~ +/v { currentpoint 6 2 roll curveto } 4 ! +/y { 2 copy curveto } 4 ! +/re + { 4 2 roll moveto exch dup 0 rlineto 0 3 -1 roll rlineto neg 0 rlineto + closepath + } 4 ! + +% ---------------- Path painting and clipping ---------------- % + +/S_ { setstrokecolor /stroke fsexec } bdef +/S { S_ } 0 ! +/f { setfillcolor /fill fsexec } 0 ! +/f* { setfillcolor /eofill fsexec } 0 ! +/n_ { newpath } bdef % don't allow n_ to get bound in +/n { n_ } 0 ! +/s { closepath S_ } 0 ! +/B_ { gsave setfillcolor fill grestore S_ } bdef +/B /B_ load 0 ! +/b { closepath B_ } 0 ! +/B*_ { gsave setfillcolor eofill grestore S_ } bdef +/B* /B*_ load 0 ! +/b* { closepath B*_ } 0 ! + +% Clipping: + +/Wdict 4 dict dup begin +/S_ { gsave setstrokecolor stroke grestore n_ } bdef +/f { gsave setfillcolor fill grestore n_ } 0 ! +/f* { gsave setfillcolor eofill grestore n_ } 0 ! +/n_ { end clip newpath } bdef +end readonly def +/W { //Wdict begin } 0 ! +/W*dict 4 dict dup begin +/S_ { gsave setstrokecolor stroke grestore n_ } bdef +/f { gsave setfillcolor fill grestore n_ } 0 ! +/f* { gsave setfillcolor eofill grestore n_ } 0 ! +/n_ { end eoclip newpath } bdef +end readonly def +/W* { //W*dict begin } 0 ! + +% ---------------- Images ---------------- % + +% We mustn't bind these now, since they reference Level 2 operators. +/Is % Is + { dup /DataSource get string /readstring cvx /currentfile cvx + % Stack: imagedict string -readstring- -currentfile- + 3 index /FilterProc .knownget + { dup dup 0 get /ASCIIHexDecode eq exch length 2 eq and + { pop exch pop /readhexstring cvx exch } + { exch exec exch exec } + ifelse + } + if 3 1 roll /pop cvx 4 packedarray cvx + } bdef +/EI { } def % placeholder, only needed when writing PostScript +% Note that ID* take a dictionary, not separate values; +% ColorSpace must be a name if it has no parameters; +% DataSource is the size of the row buffer in bytes; +% FilterProc is an optional procedure for constructing the decoding filter; +% and ImageMask is required, not optional. +/csimage + { /setcolorspace where + { pop dup /ColorSpace get csset setcolorspace pop image } + { .colorspaceimage } + ifelse + } def % don't bind, because of Level 2 +/ID % ID - + { Is dup 3 -1 roll dup /ImageMask get + { setfillcolor dup /Interpolate .knownget not { false } if + { dup /DataSource 4 -1 roll put /imagemask cvx exec + } + { { /Width /Height /Decode /ImageMatrix } + { 1 index exch get exch } + forall pop exch 0 get 0 ne exch + 5 -1 roll imagemask + } + ifelse + } + { dup /ColorSpace get /DeviceGray eq + 1 index /BitsPerComponent get 8 le and + 1 index /Decode get dup 1 get 1 eq exch 0 get 0 eq and and + 1 index /Interpolate .knownget not { false } if not and + { { /Width /Height /BitsPerComponent /ImageMatrix } + { 1 index exch get exch } + forall pop 5 -1 roll image + } + { dup /DataSource 4 -1 roll put csimage + } + ifelse + } + ifelse + % If we were reading with readhexstring, + % skip the terminating > now. + % Stack: datasource + dup type /filetype ne % array or packedarray + { dup 2 get /readhexstring eq + { { dup 0 get exec read pop (>) 0 get eq { exit } if } loop + } + if pop + } + { pop + } + ifelse EI + } 1 ! +% IDx handles general images. +/IDx % IDx - + { Is 1 index /DataSource 3 -1 roll put + csimage EI + } 1 ! + +% ---------------- Text control ---------------- % + +/textbeginpage + { /TextSpacing 0 def % 0 Tc + /TextLeading 0 def % 0 TL + /TextRenderingMode 0 def % 0 Tr + /TextRise 0 def % 0 Ts + /WordSpacing 0 def % 0 Tw + /TextHScaling 1.0 def % 100 Tz + /TextFont null def + /Show { showfirst } def + } bdef + +% Contrary to the statement in the PDF manual, BT and ET *can* be nested, +% if the CharProc for a Type 3 font does a BT/ET itself. +% Since we always call the CharProc inside a q_/Q_, we simply ensure that +% the text state is saved and restored like the rest of the extended +% graphics state. + +/settextmatrix + { TextMatrix concat + TextHScaling 1 ne { TextHScaling 1 scale } if + TextRise 0 ne { 0 TextRise translate } if + } bdef +/settextstate { TextSaveMatrix setmatrix settextmatrix } bdef + +/BT + { currentdict /TextMatrix .knownget + { identmatrix pop } + { matrix /TextMatrix gput } + ifelse + currentdict /TextOrigin .knownget + { dup 0 0 put 1 0 put } + { [0 0] cvx /TextOrigin gput } + ifelse + { showfirst } /Show gput + currentdict /TextSaveMatrix .knownget not + { matrix dup /TextSaveMatrix gput } + if currentmatrix pop settextmatrix 0 0 moveto + TextFont dup null eq { pop } { setfont } ifelse + } bind 0 ! +/ET + { TextSaveMatrix setmatrix + } bind 0 ! +/Tc_ { /TextSpacing gput { showfirst } /Show gput } bdef +/Tc { Tc_ } 1 ! +/TL { /TextLeading gput } bind 1 ! +/Tr { /TextRenderingMode gput { showfirst } /Show gput } bind 1 ! +/Ts { /TextRise gput settextstate } bind 1 ! +/Tw_ { /WordSpacing gput { showfirst } /Show gput } bdef +/Tw { Tw_ } 1 ! +/Tz { 100 div /TextHScaling gput settextstate } bind 1 ! + +/Tf % Tf - + { dup 1 eq { pop } { scalefont } ifelse + dup setfont /TextFont gput + } 2 ! + +% Copy a font, removing its FID. If changed is true, also remove +% the UniqueID and XUID, if any. If the original dictionary doesn't have +% the keys being removed, don't copy it. +/.copyfontdict % .copyfontdict + { 1 index /FID known + 1 index { 2 index /UniqueID known or 2 index /XUID known or } if + { % We add 1 to the length just in case the original + % didn't have a FID. + exch dup length 1 add dict exch + { % Stack: changed newfont key value + 1 index /FID eq 4 index + { 2 index /UniqueID eq or 2 index /XUID eq or } + if not { 3 copy put } if pop pop + } + forall exch + } + if pop + } bdef + +% Insert a new Encoding or Metrics into a font if necessary. +% Return a possibly updated font, and a flag to indicate whether +% the font was actually copied. +/.updatefont % .updatefont + % + { 2 index 4 1 roll + dup null ne + { 3 -1 roll true .copyfontdict dup /Metrics 4 -1 roll put exch } + { pop } + ifelse + dup null ne 1 index 3 index /Encoding get ne and + { exch false .copyfontdict dup /Encoding 4 -1 roll put } + { pop } + ifelse exch 1 index ne + } bdef + +% ---------------- Text positioning ---------------- % + +/Td_ + { TextOrigin exch 4 -1 roll add 3 1 roll add + 2 copy /TextOrigin load astore pop moveto + } bdef +/Td { Td_ } 2 ! +/TD { dup neg /TextLeading gput Td_ } 2 ! +/T*_ { 0 TextLeading neg Td_ } bdef +/T* { T*_ } 0 ! +/Tm + { TextMatrix astore pop settextstate + 0 0 /TextOrigin load astore pop + 0 0 moveto + } 6 ! + +% ---------------- Text painting ---------------- % + +/textrenderingprocs [ % (0 is handled specially) + { tf } { tS } { tB } { tn } + % We don't know what the clipping modes mean.... + 4 copy +] readonly def +/setshowstate + { WordSpacing 0 eq TextSpacing 0 eq and + { TextRenderingMode 0 eq + { { setfillcolor show } } + { { false charpath textrenderingprocs TextRenderingMode get exec } } + ifelse + } + { TextRenderingMode 0 eq + { WordSpacing 0 eq + { { setfillcolor TextSpacing exch 0 exch ashow } } + { TextSpacing 0 eq + { { setfillcolor WordSpacing exch 0 exch 32 exch widthshow } } + { { setfillcolor WordSpacing exch TextSpacing exch 0 32 4 2 roll 0 exch awidthshow } } + ifelse + } + ifelse + } + { { WordSpacing TextSpacing 2 index + % Implement the combination of t3 and false charpath. + % Stack: xword xchar string + 0 1 2 index length 1 sub + { 2 copy 1 getinterval false charpath + % Stack: xword xchar string i + 4 copy get 32 eq { add } { exch pop } ifelse 0 rmoveto + pop + } + for pop pop pop pop + textrenderingprocs TextRenderingMode get exec + } + } + ifelse + } + ifelse /Show gput + } bdef +/showfirst { setshowstate Show } def + +/Tj { Show } 1 ! +/' { T*_ Show } 1 ! +/" { exch Tc_ exch Tw_ T*_ Show } 3 ! +% TJ expects a mark followed by arguments, not an array. +/TJ + { counttomark -1 1 + { -1 roll dup type /stringtype eq + { Show } + { neg 1000 div 0 rmoveto } + ifelse + } + for pop +% Adobe implementations don't accept /[, so we don't either. + } ([) cvn ! + +/tf { setfillcolor currentpoint fill moveto } bdef +/tn { currentpoint newpath moveto } bdef +% For stroking characters, temporarily restore the graphics CTM so that +% the line width will be transformed properly. +/Tmatrix matrix def +/tS + { setstrokecolor + currentpoint //Tmatrix currentmatrix TextSaveMatrix setmatrix stroke + setmatrix moveto + } bdef +/tB { gsave tf grestore tS } bdef + +end readonly put % GS_PDF_ProcSet + +setglobal diff --git a/pstoraster/gs_pdf_e.ps b/pstoraster/gs_pdf_e.ps new file mode 100644 index 0000000000..ca1e934d26 --- /dev/null +++ b/pstoraster/gs_pdf_e.ps @@ -0,0 +1,48 @@ +% Copyright (C) 1994 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Define the PDFDoc encoding vector. +/currentglobal where + { pop currentglobal { setglobal } true setglobal } + { { } } +ifelse +/PDFDocEncoding +ISOLatin1Encoding 0 24 getinterval aload pop + /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde +ISOLatin1Encoding 32 7 getinterval aload pop + /quotesingle +ISOLatin1Encoding 40 56 getinterval aload pop + /grave +ISOLatin1Encoding 97 31 getinterval aload pop +% \20x + /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction + /guilsinglleft /guilsinglright /minus /perthousand + /quotedblbase /quotedblleft /quotedblright /quoteleft + /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron + /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron /.notdef +% \24x + /.notdef +ISOLatin1Encoding 161 12 getinterval aload pop + /.notdef +ISOLatin1Encoding 174 82 getinterval aload pop +256 packedarray .defineencoding +exec diff --git a/pstoraster/gs_pdfwr.ps b/pstoraster/gs_pdfwr.ps new file mode 100644 index 0000000000..6b982bdecf --- /dev/null +++ b/pstoraster/gs_pdfwr.ps @@ -0,0 +1,288 @@ +% Copyright (C) 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% gs_pdfwr.ps +% PDF writer additions to systemdict. + +% This file should be included iff the pdfwrite "device" is included +% in the executable. + +% Redefine pdfmark to pass the data to the driver. +/.pdf===dict mark + /arraytype + { dup xcheck { ({) (}) } { ([) (]) } ifelse + % Stack: file obj left right + 4 1 roll 2 index exch writestring () exch + { exch 2 index exch writestring + 1 index exch pdfmark===only ( ) + } + forall pop exch writestring + } bind + /packedarraytype 1 index + /dicttype + { 1 index (<<\n) writestring + { 2 index 3 -1 roll pdfmark===only 1 index ( ) writestring + 1 index exch pdfmark===only dup (\n) writestring + } + forall (>>) writestring + } bind +.dicttomark readonly def +/pdfmark===only % pdfmark===only - + { .pdf===dict 1 index type .knownget { exec } { write==only } ifelse + } bind def +/.pdfcvs % .pdfcvs + { % We can't handle long values yet. + =string /NullEncode filter dup 2 index pdfmark===only + dup (\n\000) writestring closefile pop + =string (\n\000) search + { dup length string copy exch pop exch pop } + { % The converted representation didn't fit. Punt. + pop (???) + } + ifelse + } bind def +/.pdfputparams % .pdfputparams + { currentdevice null false mark 6 -2 roll exch + % Don't allow the page device to get cleared.... + {.putdeviceparams} 0 get .currentpagedevice pop {.setpagedevice} 0 get + 3 array astore cvx exec + } bind def +/pdfmark + { ] 1 2 2 index length 1 sub { 2 copy 2 copy get .pdfcvs put pop } for + /pdfmark .pdfputparams + type /booleantype ne { cleartomark pop pop } if pop + } odef +userdict /pdfmark .undef + +% Define setdistillerparams / currentdistillerparams. +% Distiller parameters are currently treated as device parameters. +/.distillerparamkeys mark + % General parameters + /CoreDistVersion { } + /DoThumbnails { } + /LZWEncodePages { } + /ASCII85EncodePages { } + % Color sampled image parameters + /DownsampleColorImages { } + /ColorImageResolution { } + /EncodeColorImages { } + /ColorImageFilter { } + /ColorImageDict { } + /ColorImageDepth { } + /AntiAliasColorImages { } + /ConvertCMYKImagesToRGB { } + % Grayscale sampled image parameters + /DownsampleGrayImages { } + /GrayImageResolution { } + /EncodeGrayImages { } + /GrayImageFilter { } + /GrayImageDict { } + /GrayImageDepth { } + /AntiAliasGrayImages { } + % Monochrome sampled image parameters + /DownsampleMonoImages { } + /MonoImageResolution { } + /EncodeMonoImages { } + /MonoImageFilter { } + /MonoImageDict { } + /MonoImageDepth { } + /AntiAliasMonoImages { } + % Font embedding parameters + /AlwaysEmbed + { dup length 0 gt + { dup 0 get false eq + { dup length 1 sub 1 exch getinterval exch pop /~AlwaysEmbed exch + } if + } if + } + /NeverEmbed + { dup length 0 gt + { dup 0 get false eq + { dup length 1 sub 1 exch getinterval exch pop /~NeverEmbed exch + } if + } if + } + /EmbedAllFonts { } + /SubsetFonts { } + /MaxSubsetPct { } +.dicttomark readonly def +/.distillerdevice + { currentdevice .devicename /pdfwrite eq + { currentdevice } + { /pdfwrite finddevice } + ifelse + } bind def +/setdistillerparams % setdistillerparams - + { .distillerdevice null false mark 5 -1 roll + { //.distillerparamkeys 2 index .knownget { exec } { pop pop } ifelse } + forall .putdeviceparams + type /booleantype eq { pop } { cleartomark pop pop pop } ifelse + } odef +/currentdistillerparams % - currentdistillerparams + { .distillerdevice //.distillerparamkeys .getdeviceparams .dicttomark + } odef + +% Patch the 'show' operators to pass the data to the device. +% We use a pseudo-parameter named /show whose value is a dictionary: +% /String (str) +% /Values [cx cy char ax ay px py] +% /Matrix [xx xy yx yy tx ty] +% /FontName /fontname +% /Color [r g b] +% /Encoding [e0 .. e255] +% /BaseEncoding [e0 ... e255] +% THIS IS A BIG HACK. +/.findorigfont % .findorigfont + { % Check for a known font with this name and + % the same UniqueID. + dup /UniqueID .knownget + { 1 index /FontName .knownget + { % Stack: font uniqueid fontname + FontDirectory exch .knownget + { dup /UniqueID .knownget + { % Stack: font uniqueid knownfont knownid + 3 -1 roll eq { true } { pop false } ifelse + } + { pop pop false + } + ifelse + } + { pop false + } + ifelse + } + { pop false + } + ifelse + } + { false + } + ifelse + % Stack: font knownfont -true- | font -false- + { exch pop + } + { { dup /OrigFont .knownget not { exit } if exch pop } loop + } + ifelse + } .bind def +/.pdfdoshow % .pdfdoshow + % + { mark /String 8 2 roll + currentpoint transform 7 array astore /Values exch + % Concatenate the "quotient" of the current FontMatrix + % and the FontMatrix of the original font. + % Be sure to include any translation. + /Matrix + currentfont .findorigfont /FontMatrix get matrix invertmatrix + currentfont /FontMatrix get 1 index concatmatrix + matrix currentmatrix dup 4 0 put dup 5 0 put dup concatmatrix + /FontName currentfont /FontName get + /Color [ currentrgbcolor ] + /Encoding currentfont /Encoding .knownget not { [] } if + % Make a reasonable guess at the base encoding. + /BaseEncoding StandardEncoding + .dicttomark /show .pdfputparams + dup type /booleantype eq + { pop pop true } + { dup /undefined eq + { cleartomark pop pop pop false } + { dup mark eq { /unknown /rangecheck } if + counttomark 4 add 1 roll cleartomark pop pop pop + /.pdfshow cvx exch signalerror + } + ifelse + } + ifelse + } .bind def +/.pdfexecshow % .pdfexecshow - + { matrix currentmatrix gsave nulldevice setmatrix + exec currentpoint grestore moveto + } .bind def +% Create a 1-element cache for currentdevice .devicename /pdfwrite eq. +userdict begin + /.pdfwritedevice null def + /.pdfwriteenabled false def % place-holder +end +/.pdfwrite? % - .pdfwrite? + { currentdevice .pdfwritedevice eq + { .pdfwriteenabled + } + { currentdevice .devicename /pdfwrite eq + userdict /.pdfwriteenabled 2 index put + userdict /.pdfwritedevice currentdevice put + } + ifelse currentfont /FontType get 1 eq and + } .bind def +/.pdfshow % + % .pdfdoshow - + { 7 1 roll .pdfwrite? + { .pdfdoshow } + { 6 { pop } repeat false } + ifelse + { .pdfexecshow } + { exec } + ifelse + } .bind def +/show + { dup 0 0 32 0 0 { show } .pdfshow + } .bind odef +/ashow + { dup 0 0 32 6 index 6 index dtransform { ashow } .pdfshow + } .bind odef +/widthshow + { 4 copy 4 -2 roll dtransform 4 -1 roll 0 0 { widthshow } .pdfshow + } .bind odef +/awidthshow + { 6 copy 6 -2 roll dtransform 6 -3 roll dtransform { awidthshow } .pdfshow + } .bind odef +/glyphshow + { .pdfwrite? + { currentfont /Encoding .knownget not { {} } if + 0 1 2 index length 1 sub + { % Stack: glyph encoding index + 2 copy get 3 index eq { exch pop exch pop null exit } if pop + } + for null eq + { (X) dup 0 4 -1 roll put show } + { glyphshow } + ifelse + } + { glyphshow + } + ifelse + } .bind odef +% The remaining operators aren't implemented correctly. +/kshow + { .pdfwrite? + { { (X) dup 0 4 -1 roll put show dup exec } forall pop } + { kshow } + ifelse + } .bind odef +/xshow + { .pdfwrite? { pop show } { xshow } ifelse + } .bind odef +/yshow + { .pdfwrite? { pop show } { yshow } ifelse + } .bind odef +/xyshow + { .pdfwrite? { pop show } { xyshow } ifelse + } .bind odef diff --git a/pstoraster/gs_pfile.ps b/pstoraster/gs_pfile.ps new file mode 100644 index 0000000000..5d49a64480 --- /dev/null +++ b/pstoraster/gs_pfile.ps @@ -0,0 +1,184 @@ +% Copyright (C) 1994, 1995 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Runtime support for minimum-space fonts and packed files. + +% ****** NOTE: This file must be kept consistent with +% ****** packfile.ps and wrfont.ps. + +% ---------------- Packed file support ---------------- % + +% A packed file is the concatenation of several file groups, each of which +% is the result of compressing several files concatenated together. +% The packed file begins with a procedure that creates an appropriate +% decoding filter for each file group, as follows: +% -proc- +% Thus, accessing an individual file requires 4 parameters: +% the starting address and length of the outer compressed file, +% and the starting address and length of the inner file. +/.packedfilefilter % + % .packedfilefilter + { 4 index systemdict begin token pop end 6 1 roll + % Stack: fproc file ostart olength istart ilength + 4 index 5 -1 roll setfileposition + % Stack: fproc file olength istart ilength + 4 -2 roll () /SubFileDecode filter + % Stack: fproc istart ilength ofilter + 4 -1 roll exec + % Filters don't support setfileposition, so we must skip data + % by reading it into a buffer. We rely on the fact that + % save/restore don't affect file positions. + % Stack: istart ilength dfilter + save exch 1000 string + % Stack: istart ilength save dfilter scratch + 4 index 1 index length idiv { 2 copy readstring pop pop } repeat + 2 copy 0 8 -1 roll 2 index length mod getinterval readstring pop pop pop + % Stack: ilength save dfilter + exch restore exch () /SubFileDecode filter + } bind def + +% Run a packed library file. +/.runpackedlibfile % + % .runpackedlibfile + { 5 -1 roll findlibfile + { exch pop dup 6 2 roll .packedfilefilter + currentobjectformat exch 1 setobjectformat run + setobjectformat closefile + } + { 5 1 roll /findlibfile load /undefinedfilename signalerror + } + ifelse + } bind def + +% ---------------- Compacted font support ---------------- % + +% Compacted fonts written by wrfont.ps depend on the existence and +% specifications of the procedures and data in this section. + +/.compactfontdefault mark + /PaintType 0 + /FontMatrix [0.001 0 0 0.001 0 0] readonly + /FontType 1 + /Encoding StandardEncoding +.dicttomark readonly def + +/.checkexistingfont % + % .checkexistingfont + % {} ( on d-stack) + % + % .checkexistingfont + % -save- --restore-- ( on d-stack) + { FontDirectory 4 index .knownget + { dup /UniqueID .knownget + { 4 index eq exch /FontType get 1 eq and } + { pop false } + ifelse + } + { false + } + ifelse + { save /restore load 6 2 roll } + { {} 5 1 roll } + ifelse + dict //.compactfontdefault exch .copydict begin + dict /Private exch def + Private begin + /MinFeature {16 16} def + /Password 5839 def + /UniqueID 1 index def + end + /UniqueID exch def + /FontName exch def + } bind def + +/.knownEncodings [ + ISOLatin1Encoding + StandardEncoding + SymbolEncoding +] readonly def + +/.readCharStrings % .readCharStrings + { exch dup dict dup 3 -1 roll + { currentfile token pop dup type /integertype eq + { dup -8 bitshift //.knownEncodings exch get exch 255 and get } if + currentfile token pop dup type /nametype eq + { 2 index exch get + } + { % Stack: encrypt dict dict key value + 4 index { 4330 exch dup .type1encrypt exch pop } if + readonly + } + ifelse put dup + } + repeat pop exch pop + } bind def + +% ---------------- Synthetic font support ---------------- % + +% Create a new font by modifying an existing one. paramdict contains +% entries with the same keys as the ones found in a Type 1 font; +% it should also contain enough empty entries to allow adding the +% corresponding non-overridden entries from the original font dictionary, +% including FID. If paramdict includes a FontInfo entry, this will +% also override the original font's FontInfo, entry by entry; +% again, it must contain enough empty entries. + +% Note that this procedure does not perform a definefont. + +/.makemodifiedfont % .makemodifiedfont + { exch + { % Stack: destdict key value + 1 index /FID ne + { 2 index 2 index known + { % Skip fontdict entry supplied in paramdict, but + % handle FontInfo specially. + 1 index /FontInfo eq + { 2 index 2 index get % new FontInfo + 1 index % old FontInfo + { % Stack: destdict key value destinfo key value + 2 index 2 index known + { pop pop } + { 2 index 3 1 roll put } + ifelse + } + forall pop + } + if + } + { % No override, copy the fontdict entry. + 2 index 3 1 roll put + dup dup % to match pop pop below + } + ifelse + } + if + pop pop + } forall + } bind def + +% Make a modified font and define it. Note that unlike definefont, +% this does not leave the font on the operand stack. + +/.definemodifiedfont % .definemodifiedfont - + { .makemodifiedfont + dup /FontName get exch definefont pop + } bind def diff --git a/pstoraster/gs_res.ps b/pstoraster/gs_res.ps new file mode 100644 index 0000000000..6b955e9016 --- /dev/null +++ b/pstoraster/gs_res.ps @@ -0,0 +1,555 @@ +% Copyright (C) 1994, 1996 Aladdin Enterprises. All rights reserved. +% +% This file is part of GNU Ghostscript. +% +% GNU Ghostscript is distributed in the hope that it will be useful, but +% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to +% anyone for the consequences of using it or for whether it serves any +% particular purpose or works at all, unless he says so in writing. Refer to +% the GNU General Public License for full details. +% +% Everyone is granted permission to copy, modify and redistribute GNU +% Ghostscript, but only under the conditions described in the GNU General +% Public License. A copy of this license is supposed to have been given to +% you along with GNU Ghostscript so you can know your rights and +% responsibilities. It should be in a file named COPYING. Among other +% things, the copyright notice and this notice must be preserved on all +% copies. +% +% Aladdin Enterprises is not affiliated with the Free Software Foundation or +% the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, +% does not depend on any other GNU software. + +% Initialization file for Level 2 resource machinery. +% When this is run, systemdict is still writable, +% but everything defined here goes into level2dict. + +level2dict begin + +(BEGIN RESOURCES) VMDEBUG + +% We keep track of (global) instances with another entry in the resource +% dictionary, an Instances dictionary. For categories with implicit +% instances, the values in Instances are the same as the keys; +% for other categories, the values are [instance status size]. + +% Note that the dictionary that defines a resource category is stored +% in global memory. The PostScript manual says that each category must +% manage global and local instances separately. However, objects in +% global memory other than systemdict can't reference objects in local memory. +% This means that the resource category dictionary, which would otherwise be +% the obvious place to keep track of the instances, can't be used to keep +% track of local instances. Instead, we define a dictionary in local VM +% called localinstancedict, in which the key is the category name and +% the value is the analogue of Instances for local instances. + +% We don't currently implement automatic resource unloading. +% When and if we do, it should be hooked to the garbage collector. +% However, Ed Taft of Adobe says their interpreters don't implement this +% either, so we aren't going to worry about it for a while. + +currentglobal false setglobal systemdict begin + /localinstancedict 5 dict def +end true setglobal +/.emptydict 0 dict readonly def +setglobal + +% Resource category dictionaries have the following keys (those marked with +% * are optional): +% Standard, defined in the Red Book: +% Category (name) +% *InstanceType (name) +% DefineResource +% UndefineResource +% FindResource +% ResourceStatus +% ResourceForAll +% *ResourceFileName +% Additional, specific to our implementation: +% Instances (dictionary) +% .LocalInstances +% - .LocalInstances +% .GetInstance +% .GetInstance -true- +% .GetInstance -false- +% .CheckResource +% .CheckResource +% .DoLoadResource +% .DoLoadResource - (may give an error) +% .LoadResource +% .LoadResource - (may give an error) +% .ResourceFile +% .ResourceFile -true- +% .ResourceFile -false- +% All the above procedures expect that the top dictionary on the d-stack +% is the resource dictionary. + +% Define enough of the Category category so we can define other categories. +% The dictionary we're about to create will become the Category +% category definition dictionary. + +12 dict begin + + % Standard entries + +/Category /Category def +/InstanceType /dicttype def + +/DefineResource + { dup .CheckResource + { dup /Category 3 index cvlit .growput readonly + dup [ exch 0 -1 ] exch + Instances 4 2 roll put + } + { /typecheck signalerror + } + ifelse + } bind def +/FindResource % (redefined below) + { Instances exch get 0 get + } bind def + + % Additional entries + +/Instances 25 dict def +Instances /Category [currentdict 0 -1] put + +/.LocalInstances 0 dict def +/.GetInstance + { Instances exch .knownget + } bind def +/.CheckResource + { dup gcheck currentglobal and + { /DefineResource /FindResource /ResourceForAll /ResourceStatus + /UndefineResource } + { 2 index exch known and } + forall exch pop + } bind def + +Instances end begin % for the base case of findresource + +(END CATEGORY) VMDEBUG + +% Define the resource operators. I don't see how we can possibly restore +% the stacks after an error, since the procedure may have popped and +% pushed elements arbitrarily.... + +mark +/defineresource % defineresource + { /Category findresource dup begin + /InstanceType known + { dup type InstanceType ne + { dup type /packedarraytype eq InstanceType /arraytype eq and + not { /typecheck signalerror } if + } if + } if + /DefineResource load stopped end { stop } if + } +/findresource % findresource + { dup /Category eq + { pop //Category 0 get } { /Category findresource } ifelse + begin + /FindResource load stopped end { stop } if + } +/resourceforall %