From: msweet Date: Fri, 10 May 2013 18:56:23 +0000 (+0000) Subject: Import cups.org releases X-Git-Tag: release-1.1b2^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=145d01c94688787b05a135d3578e66f7c3322cfd;p=thirdparty%2Fcups.git Import cups.org releases git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/tags/release-1.1b2@4306 a1ca3aef-8c08-0410-bb20-df032aa958be --- 145d01c94688787b05a135d3578e66f7c3322cfd diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000000..2606119955 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,299 @@ +CHANGES.txt - 03/13/2000 +------------------------ + +CHANGES IN CUPS v1.1b2 + + - Documentation updates. + - The lp command didn't always load the user-defined + destinations, preventing it from seeing the default + printer. + - Many configure script and makefile fixes. + - The Microsoft code page files were missing from the + distribution. + - Added a workaround for the HP IPP client (which is sending + an invalid printer-uri in requests) + - Fixed the encoding of text-with-language and name-with-language + to match the IPP spec. + - Added support for unknown value tags in the IPP routines + (previously they would be ignored) + - Integrated GNU GhostScript 5.50 into the pstoraster filter. + - Client hostname resolution was broken on little-endian + machines. + - Now look at client.conf file for client's default server + and printer. + - The cupsServer() function did not close the client.conf file + if it contained a ServerName directive. + - Added BrowseAllow, BrowseDeny, BrowseOrder, BrowsePoll, and + BrowseRelay directives. + - BrowseInterval 0 disables advertising of local printers, but + still receives information on remote printers. + - New browse polling daemon (for polling servers on different + networks) + - New PPD cache file for faster startup times with large numbers + of PPD files. + - The Host: field was incorrectly required for HTTP/1.0 clients. + - New set-job-attributes operation now supported. + - The mime_load_types() and mime_load_convs() functions did not + close their input files. + + +CHANGES IN CUPS v1.1b1 + + - NEW web-based administration interface. + - NEW EPSON printer drivers. + - NEW user-defined printers and options. + - NEW persistent jobs and job history + - NEW IPP/1.1 support + - NEW template-based web interfaces. + - NEW CUPS-get-devices and CUPS-get-ppds operations. + - NEW support for create-job and send-file operations. + - NEW certificate-based authentication for local + administration. + - NEW USB backend. + - The lpr command now produces human-readable error messages. + - The lpq command now produces BSD standard format output + instead of OSF/1 output. This should resolve the SAMBA + print queue problems that have been reported. + - The IPP backend did not always detect when the "raw" option + was being used. + - The "lpstat -p" command would stop after the first active + printer. + - The "lpstat -v" command would stop before the first remote + printer. + + +CHANGES IN CUPS v1.0.5 + + - The HP-GL/2 filter did not correctly set the pen color + for pens other than #1. + - The scheduler would only accept 26 simultaneous jobs + under some OS releases (mkstemp() limitation.) It now + handles up to 2^32 simultaneous jobs. + - The PostScript filter loaded the printer's PPD file + twice. + - The PAM authentication code now uses pam_strerror() to + provide a textual error message in the error_log file. + - The scheduler now copies PPD and interface script + files instead of moving them; this fixes installations + with a separate requests directory. + - The PostScript RIP did not generate correct 6-color + output. + - Several filters were marking PPD options twice when + they didn't need to. + - The scheduler did not save the printer or class state + after an accept-jobs or reject-jobs operation. + - The cupsGetDefault() function now ignores the PRINTER + environment variable if it is set to "lp". + - New ippErrorString() function to get textual error + messages. + - Better error reporting in the System V commands. + - The lpadmin and lpstat commands always tried to + connect to the default server. + - The text filter didn't load the charset files from the + correct location. + - Wasn't sending a WWW-Authenticate: field to HTTP + clients when authentication was required. + - httpSeparate() didn't always set the default port + number for known methods. + - The HP-GL/2 filter now looks for "PSwidth,length" + instead of (the correct) "PSlength,width" as + documented by HP. It appears that many major CAD + applications are broken and this change allows the + auto-rotation to work with them. + - The IPP "printer-resolution" option was not being + translated. + - The charset files did not include the Microsoft + "standard" characters from 128 to 159 (unused by the + ISO-8859-x charsets) + - The scheduler was chunking the Content-Type field from + CGI programs; this problem was most noticeable with + Microsoft Internet Explorer 5. + - By popular demand, the printers, jobs, and classes + CGIs no longer force a reload of the page every 10/30 + seconds. + - The scheduler incorrectly required that the IPP client + provide a document-format attribute for the + validate-job operation. + - Clients that sent bad IPP requests without the + required attributes-natural-language and + attributes-charset attributes would crash the + scheduler. + + +CHANGES IN CUPS v1.0.4 + + - Documentation updates. + - Jobs would get stuck in the queue and wouldn't print + until you enabled the queue. + - The lp and lpr commands now catch SIGHUP and SIGINTR. + - The lp and lpr commands now use sigaction or sigset + when available. + - CUPS library updates for WIN32/OS-2 + + +CHANGES IN CUPS v1.0.3 + + - Documentation updates. + - The lpq man page was missing. + - The configure script was not properly detecting the + image libraries. + - The top-level makefile was calling "make" instead of + "$(MAKE)". + - PostScript filter fixes for number-up, OutputOrder, + and %Trailer. + - The imagetops filter didn't end the base-85 encoding + properly if the image data was not a multiple of 4 + bytes in length. + - The imagetoraster filter didn't generate good banded + RGB or CMY data (was dividing the line width by 4 + instead of 3...) + - The imagetoraster filter now records the bounding + box of the image on the page. + - The CUPS image library cache code wasn't working as + designed; images larger than the maximum RIP cache + would eventually thrash using the same cache tile. + - The CUPS image library TIFF loading code didn't + handle unknown resolution units properly; the fixed + code uses a default resolution of 128 PPI. + - cupsGetClasses() and cupsGetPrinters() did not free + existing strings if they ran out of memory. + - The scheduler logs incorrectly contained 3 digits for + the timezone offset instead of 4. + - The scheduler now does a lookup for the default user + and group ID; the previous hardcoded values caused + problems with the LPD backend. + - The cancel-job operation now allows any user in the + system group to cancel any job. + - The cancel-job operation stopped the print queue if + the job was being printed. + - Now only stop printers if the backend fails. If the + filter fails then the failure is noted in the + error_log and printing continues with the next file in + the queue. + - Now log whether a filter fails because of a signal + or because it returned a non-zero exit status. + - The root user now always passes the system group test. + - Printers with an interface script and remote printers + and classes didn't have a printer-make-and-model + attribute. + - Added logging of lost/timed-out remote printers. + - The HP-GL/2 filter was scaling the pen width twice. + - Updated the HP-GL/2 filter to use a single SP (Set + Pen) procedure. This makes the output smaller and is + more appropriate since the filter keeps track of the + pen states already. + - The scheduler didn't handle passwords with spaces. + - The IPP backend now does multiple copies and retries + if the destination server requires it (e.g. HP + JetDirect.) + - The disable command didn't implement the "-c" option + (cancel all jobs.) + - Changed the CMYK generation function for the image file + and PostScript RIPs. + - The lp command didn't support the "-h" option as + documented. + - The AppSocket, IPP, and LPD backends now retry on all + network errors. This should prevent stopped queues + caused by a printer being disconnected from the + network or powered off. + - The scheduler now restarts a job if the corresponding + printer is modified. + - The image RIPs now rotate the image if needed to fit + on the page. + + +CHANGES IN CUPS v1.0.2 + + - The HP-GL/2 filter didn't always scale the output + correctly. + - The HP-GL/2 filter now supports changing the page size + automatically when the "fitplot" option is not used. + - The cancel-job operation was expecting a resource name + of the form "/job/#" instead of "/jobs/#"; this + prevented the cancel and lprm commands from working. + - The backends didn't log pages when files were printed + using the "-oraw" option. + - The authorization code did not work with the Slackware + long shadow password package because its crypt() can + return NULL. + - The chunking code didn't work for reading the response + of a POST request. + - cupsGetPPD() now does authentication as needed. + - The N-up code in the PostScript filter didn't work + with some printers (grestoreall would restore the + default blank page and device settings). + - The N-up code in the PostScript filter didn't scale + the pages to fit within the imageable area of the + page. + - Wasn't doing an fchown() on the request files. This + caused problems when the default root account group + and CUPS group were not the same. + + +CHANGES IN CUPS v1.0.1 + + - Documentation updates. + + - Fixed a bunch of possible buffer-overflow conditions. + + - The scheduler now supports authentication using PAM. + + - Updated the Italian message file. + + - httpEncode64() didn't add an extra "=" if there was + only one byte in the last three-byte group. + + - Now drop any trailing character set from the locale + string (e.g. "en_US.ISO_8859-1" becomes "en_US") + + - Fixed "timezone" vs "tm_gmtoff" usage for BSD-based + operating systems. + + - Updated IPP security so that "get" operations can be + done from any resource name; this allows the CGIs to + work with printer authentication enabled so long as + authentication isn't turned on for the whole "site". + + - The IPP code didn't properly handle the "unsupported" + group; this caused problems with the HP JetDirect since + it doesn't seem to support the "copies" attribute. + + - The HTTP chunking code was missing a CR LF pair at the + end of a 0-length chunk. + + - The httpSeparate() function didn't handle embedded + usernames and passwords in the URI properly. + + - Doing "lpadmin -p printer -E" didn't restart printing + if there were pending jobs. + + - The cancel-job operation now requires either a + requesting-user-name attribute or an authenticated + username. + + - The add-printer code did not report errors if the + interface script or PPD file could not be renamed. + + - Request files are now created without world read + permissions. + + - Added a cupsLastError() function to the CUPS API to + retrieve the IPP error code from the last request. + + - Options are now case-insensitive. + + - The lpq command now provides 10 characters for the + username instead of the original (Berkeley standard) + 7. + + - The cancel command needed a local CUPS server to work + (or the appropriate ServerName in cupsd.conf) + + - The cancel and lprm commands didn't report the IPP + error if the job could not be cancelled. + + - The lp and lpr commands didn't intercept SIGTERM to + remove temporary files when printing from stdin. + + - The lp and lpr commands didn't report the IPP error if + the job could not be printed. diff --git a/CREDITS.txt b/CREDITS.txt new file mode 100644 index 0000000000..71bad14862 --- /dev/null +++ b/CREDITS.txt @@ -0,0 +1,26 @@ +CREDITS.txt - 01/27/2000 +------------------------ + +Few projects are completed by one person, and CUPS is no exception. We'd +like to thank the following individuals for their contributions: + + Nathaniel Barbour - Lots of testing and feedback. + N. Becker - setsid(). + Jean-Eric Cuendet - GhostScript filters for CUPS. + Van Dang - HTTP and IPP policeman. + Dr. ZP Han - setgid()/setuid(). + Guy Harris - *BSD shared libraries and lots of other fixes. + Wang Jian - CUPS RPM corrections. + Roderick Johnstone - Beta tester of the millenium. + Sergey V. Kovalyov - ESP Print Pro and CUPS beta tester. + Mark Lawrence - Microsoft interoperability testing. + Jason McMullan - Original CUPS RPM distributions. + Wes Morgan - *BSD fixes. + Ulrich Oldendorf - German locale. + Petter Reinholdtsen - HP-UX compiler stuff. + Stuart Stevens - HP JetDirect IPP information. + Kiko - Bug fixes. + L. Peter Deutsch - MD5 code. + +If I've missed someone, please let me know by sending an email to +"mike@easysw.com". 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..f7f31ac86c --- /dev/null +++ b/Makedefs.in @@ -0,0 +1,132 @@ +# +# "$Id$" +# +# Common makefile definitions for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2000 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 +MV = @MV@ +NROFF = @NROFF@ +RANLIB = @RANLIB@ +RM = @RM@ -f +SED = @SED@ +SHELL = /bin/sh + +# +# 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 = + +# +# 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@ +DOCDIR = @CUPS_DOCDIR@ +INCLUDEDIR = $(includedir) +LIBDIR = $(libdir) +LOCALEDIR = @CUPS_LOCALEDIR@ +LOGDIR = @CUPS_LOGDIR@ +MANDIR = @mandir@ +REQUESTS = @CUPS_REQUESTS@ +SBINDIR = @sbindir@ +SERVERBIN = @CUPS_SERVERBIN@ +SERVERROOT = @CUPS_SERVERROOT@ + +# +# Rules... +# + +.SILENT: +.SUFFIXES: .a .c .h .man .o .1 .5 .8 +.c.o: + echo Compiling $<... + $(CC) $(CFLAGS) -c $< +.man.1 .man.5 .man.8: + echo Formatting $<... + $(RM) $@ + $(NROFF) -man $< >$@ + +# +# End of "$Id$" +# diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..d4aaafcc63 --- /dev/null +++ b/Makefile @@ -0,0 +1,94 @@ +# +# "$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) -$(MAKEFLAGS)) || break;\ + done + +# +# Remove object and target files... +# + +clean: + for dir in $(DIRS); do\ + echo Cleaning in $$dir... ;\ + (cd $$dir; $(MAKE) -$(MAKEFLAGS) clean) || break;\ + done + +# +# Install object and target files... +# + +install: + for dir in $(DIRS); do\ + echo Installing in $$dir... ;\ + (cd $$dir; $(MAKE) -$(MAKEFLAGS) install) || break;\ + done + echo Installing in conf... + (cd conf; $(MAKE) -$(MAKEFLAGS) install) + echo Installing in data... + (cd data; $(MAKE) -$(MAKEFLAGS) install) + echo Installing in doc... + (cd doc; $(MAKE) -$(MAKEFLAGS) install) + echo Installing in fonts... + (cd fonts; $(MAKE) -$(MAKEFLAGS) install) + echo Installing in ppd... + (cd ppd; $(MAKE) -$(MAKEFLAGS) install) + echo Installing in templates... + (cd templates; $(MAKE) -$(MAKEFLAGS) install) + +# +# Make a software distribution... +# + +epm: + epm -v cups + +rpm: + epm -v -f rpm cups + +deb: + epm -v -f deb cups + +tardist: + epm -v -f tardist cups + +# +# End of "$Id$". +# diff --git a/README.txt b/README.txt new file mode 100644 index 0000000000..cfdcd7eae0 --- /dev/null +++ b/README.txt @@ -0,0 +1,245 @@ +README - CUPS v1.1b2 - 03/13/2000 +--------------------------------- + +************************************************************************ +************************************************************************ +**** **** +**** BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE BETA SOFTWARE **** +**** **** +************************************************************************ +************************************************************************ + +This is an official public beta release for the Common UNIX Printing +System. Since this is a beta release, we do not recommend that you +use this software on a production system. Instead, please use the +current 1.0.x release for your production systems. + +Also, currently we are only providing source code for the beta releases. +As we approach a final production ("gold") release of CUPS 1.1 we will +provide binary distributions as well. + +Please report all problems in the CUPS 1.1 beta releases to +"cups-beta@cups.org" or to the CUPS mailing list. + +Thanks for using CUPS! + + +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) +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 5.50) and an image file RIP that can be used +to support non-PostScript printers. + +CUPS is Copyright 1993-2000 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 + - 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 available from: + + http://www.easysw.com/epm + +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. + + +READING THE DOCUMENTATION + +Once you have installed the software you can access the documentation +(and a bunch of other stuff) on-line at: + + http://localhost:631 + +If you're having trouble getting that far, the documentation is located +in the "/usr/share/cups/doc" directory in the binary distributions, and +under the "doc" directory in the source archives. + +Please read the documentation before asking questions. + + +SETTING UP PRINTER QUEUES USING YOUR WEB BROWSER + +CUPS 1.1 includes a new web-based administration tool that allows you +to manage printers, classes, and jobs on your server. To access the +printer administration tools open the following URL in your browser: + + http://localhost:631/admin + +You will be asked for the administration password (root or any other +user in the sys/system/root group on your system) and then shown a +menu of available functions. + +[note: adding, deleting, and modifying classes has not been implemented in + beta 2] + + +SETTING UP PRINTER QUEUES FROM THE COMMAND-LINE + +CUPS works best with PPD (PostScript Printer Description) files. In a +pinch you can also use System V style printer interface scripts. + +Six sample PPD files are provided with this distribution that utilize +the PostScript and image file RIPs and the sample EPSON and HP printer +drivers. 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/lp0 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/lp1 -E + /usr/lib/lpadmin -p DeskJet -m deskjet.ppd -v parallel:/dev/lp2 -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 other sample drivers you can use: + + Driver PPD File + -------------------------- ------------ + HP DeskJet Series deskjet.ppd + HP LaserJet Series laserjet.ppd + EPSON Stylus Color Series stcolor.ppd + EPSON Stylus Photo Series stphoto.ppd + EPSON 9-pin Series epson9.ppd [not in beta 2] + EPSON 24-pin Series epson24.ppd [not in beta 2] + +These sample drivers provide basic printing capabilities, but generally +do not exercise the full potential of the printers or CUPS. For +commercial printer drivers 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. If you are running a version +of Linux, be sure to provide the Linux distribution you have, too. + + +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-2000 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..c57c4c83e0 --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,139 @@ +# +# "$Id$" +# +# Backend makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2000 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 + +BACKENDS = ipp lpd parallel serial socket usb +TARGETS = betest $(BACKENDS) +OBJS = betest.o ipp.o lpd.o parallel.o serial.o socket.o usb.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) + + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERBIN)/backend + $(CP) $(BACKENDS) $(SERVERBIN)/backend + $(RM) $(SERVERBIN)/backend/http + $(LN) ipp $(SERVERBIN)/backend/http + + +# +# betest +# + +betest: betest.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o betest betest.o $(LIBS) + +betest.o: ../cups/string.h ../Makedefs + + +# +# ipp +# + +ipp: ipp.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o ipp ipp.o $(LIBS) + $(RM) http + $(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 + + +# +# socket +# + +socket: socket.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o socket socket.o $(LIBS) + +socket.o: ../cups/cups.h ../Makedefs + + +# +# usb +# + +usb: usb.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o usb usb.o $(LIBS) + +usb.o: ../cups/cups.h ../Makedefs + + +# +# End of "$Id$". +# diff --git a/backend/betest.c b/backend/betest.c new file mode 100644 index 0000000000..8c68284e1e --- /dev/null +++ b/backend/betest.c @@ -0,0 +1,85 @@ +/* + * "$Id$" + * + * Backend test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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() - Run the named backend. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include + + +/* + * 'main()' - Run the named backend. + * + * Usage: + * + * betest device-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (7 or 8) */ + char *argv[]) /* I - Command-line arguments */ +{ + char backend[255]; /* Method in URI */ + + + if (argc < 7 || argc > 8) + { + fputs("Usage: betest device-uri job-id user title copies options [file]\n", + stderr); + return (1); + } + + /* + * Extract the method from the device-uri - that's the program we want to + * execute. + */ + + if (sscanf(argv[1], "%254[^:]", backend) != 1) + { + fputs("betest: Bad device-uri - no colon!\n", stderr); + return (1); + } + + /* + * Execute and return + */ + + execl(backend, argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], + NULL); + + return (1); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/ipp.c b/backend/ipp.c new file mode 100644 index 0000000000..0132e2ee09 --- /dev/null +++ b/backend/ipp.c @@ -0,0 +1,668 @@ +/* + * "$Id$" + * + * IPP backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 */ + ipp_status_t ipp_status; /* Status of IPP request */ + 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 */ + ipp_attribute_t *copies_sup; /* copies-supported 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 */ + int copies; /* Number of copies remaining */ + const char *content_type; /* CONTENT_TYPE environment variable */ + + + if (argc == 1) + { + if ((s = strrchr(argv[0], '/')) != NULL) + s ++; + else + s = argv[0]; + + printf("network %s \"Unknown\" \"Internet Printing Protocol\"\n", s); + return (0); + } + else 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 + { + strncpy(filename, argv[6], sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + } + + /* + * Open the print file... + */ + + if ((fp = fopen(filename, "rb")) == NULL) + { + perror("ERROR: Unable to open print file"); + return (1); + } + else + stat(filename, &fileinfo); + + /* + * Extract the hostname and printer name from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * Try connecting to the remote server... + */ + + do + { + fprintf(stderr, "INFO: Connecting to %s...\n", hostname); + + if ((http = httpConnect(hostname, port)) == NULL) + if (errno == ECONNREFUSED) + { + fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...", + hostname); + sleep(30); + } + else + { + perror("ERROR: Unable to connect to IPP host"); + sleep(30); + } + } + while (http == NULL); + + /* + * 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... + */ + + snprintf(uri, sizeof(uri), "%s://%s:%d%s", method, hostname, port, resource); + + /* + * First validate the destination and see if the device supports multiple + * copies. We have to do this because some IPP servers (e.g. HP JetDirect) + * don't support the copies attribute... + */ + + language = cupsLangDefault(); + copies_sup = NULL; + + do + { + /* + * Build the IPP request... + */ + + 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 != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + /* + * Now fill in the HTTP request stuff... + */ + + httpClearFields(http); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); + if (username[0]) + { + httpEncode64(password, username); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, password); + } + + sprintf(buffer, "%u", ippLength(request)); + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, buffer); + + /* + * Do the request... + */ + + for (;;) + { + /* + * POST the request, retrying as needed... + */ + + if (httpPost(http, resource)) + { + fputs("INFO: Unable to POST get-printer-attributes 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, getting 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); + + ipp_status = response->request.status.status_code; + + if (ipp_status > IPP_OK_CONFLICT) + { + if (ipp_status == IPP_PRINTER_BUSY || + ipp_status == IPP_SERVICE_UNAVAILABLE) + { + fputs("INFO: Printer busy; will retry in 10 seconds...\n", stderr); + sleep(10); + } + else + { + fprintf(stderr, "ERROR: Printer will not accept print file (%x)!\n", + ipp_status); + status = HTTP_ERROR; + } + } + else if ((copies_sup = ippFindAttribute(response, "copies-supported", + IPP_TAG_RANGE)) != NULL) + { + /* + * Has the "copies-supported" attribute - does it have an upper + * bound > 1? + */ + + if (copies_sup->values[0].range.upper <= 1) + copies_sup = NULL; /* No */ + } + + ippDelete(response); + } + else + { + if (status == HTTP_ERROR) + { + fprintf(stderr, "WARNING: Did not receive the IPP response (%d)\n", + errno); + status = HTTP_OK; + ipp_status = IPP_PRINTER_BUSY; + } + else + fprintf(stderr, "ERROR: Validate request was not accepted (%d)!\n", status); + } + + httpFlush(http); + + break; + } + + if (status != HTTP_OK) + { + if (fp != stdin) + fclose(fp); + + httpClose(http); + + return (1); + } + } + while (ipp_status > IPP_OK_CONFLICT); + + /* + * See if the printer supports multiple copies... + */ + + if (copies_sup) + copies = 1; + else + copies = atoi(argv[4]); + + /* + * Then issue the print-job request... + */ + + while (copies > 0) + { + /* + * Build the IPP request... + */ + + request = ippNew(); + request->request.op.operation_id = IPP_PRINT_JOB; + 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 != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + fprintf(stderr, "DEBUG: printer-uri = \"%s\"\n", uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, argv[2]); + + fprintf(stderr, "DEBUG: requesting-user-name = \"%s\"\n", argv[2]); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, + argv[3]); + + fprintf(stderr, "DEBUG: job-name = \"%s\"\n", argv[3]); + + /* + * Handle options on the command-line... + */ + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + if (cupsGetOption("raw", num_options, options) || + ((content_type = getenv("CONTENT_TYPE")) != NULL && + strcasecmp(content_type, "application/vnd.cups-raw") == 0)) + 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"); + + if (copies_sup) + 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 (strcasecmp(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 (strncasecmp(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 (strcasecmp(s, "dpc") == 0) + ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_CM, n, n2); + else if (strcasecmp(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"); + if (username[0]) + { + httpEncode64(password, username); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, password); + } + + sprintf(buffer, "%u", ippLength(request) + (size_t)fileinfo.st_size); + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, buffer); + + /* + * Do the request... + */ + + for (;;) + { + /* + * POST the request, retrying as needed... + */ + + httpReconnect(http); + + if (httpPost(http, resource)) + { + fputs("INFO: Unable to POST print request; retrying...\n", stderr); + sleep(10); + 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... + */ + + rewind(fp); + + 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; + } + } + + 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 ((ipp_status = response->request.status.status_code) > IPP_OK_CONFLICT) + { + if (ipp_status == IPP_SERVICE_UNAVAILABLE || + ipp_status == IPP_PRINTER_BUSY) + { + fputs("INFO: Printer is busy; retrying print job...\n", stderr); + sleep(10); + } + else + 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; + ipp_status = IPP_PRINTER_BUSY; + + if (status == HTTP_ERROR) + { + fprintf(stderr, "WARNING: Did not receive the IPP response (%d)\n", + errno); + status = HTTP_OK; + } + else + fprintf(stderr, "ERROR: Print request was not accepted (%d)!\n", status); + } + + httpFlush(http); + + break; + } + + if (request != NULL) + ippDelete(request); + if (response != NULL) + ippDelete(response); + + if (ipp_status <= IPP_OK_CONFLICT) + { + fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1); + copies --; + } + else if (ipp_status != IPP_SERVICE_UNAVAILABLE && + ipp_status != IPP_PRINTER_BUSY) + break; + } + + /* + * Free memory... + */ + + httpClose(http); + + /* + * Close and remove the temporary file if necessary... + */ + + fclose(fp); + + if (argc < 7) + unlink(filename); + + /* + * 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..60bd578874 --- /dev/null +++ b/backend/lpd.c @@ -0,0 +1,414 @@ +/* + * "$Id$" + * + * Line Printer Daemon backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 == 1) + { + puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\""); + return (0); + } + else 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 + { + strncpy(filename, argv[6], sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + } + + /* + * Extract the hostname and printer name from the URI... + */ + + httpSeparate(argv[0], method, username, hostname, &port, resource); + + /* + * Queue the job... + */ + + if (argc > 6) + { + status = lpd_queue(hostname, resource + 1, filename, + argv[2] /* user */, atoi(argv[4]) /* copies */); + + if (!status) + fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4])); + } + else + status = lpd_queue(hostname, resource + 1, filename, + argv[2] /* user */, 1); + + /* + * 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 = vsnprintf(buf, sizeof(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 reserve port"); + sleep(30); + continue; + } + + 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"); + sleep(30); + } + } + 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 */ + + snprintf(control, sizeof(control), "H%s\nP%s\n", localhost, user); + cptr = control + strlen(control); + + while (copies > 0) + { + + snprintf(cptr, sizeof(control) - (cptr - control), "ldfA%03.3d%s\n", + getpid() % 1000, localhost); + cptr += strlen(cptr); + copies --; + } + + snprintf(cptr, sizeof(control) - (cptr - control), + "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..2c61742d0d --- /dev/null +++ b/backend/parallel.c @@ -0,0 +1,514 @@ +/* + * "$Id$" + * + * Parallel port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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. + * list_devices() - List all parallel devices. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + +#ifdef __sgi +# include +# ifndef INV_EPP_ECP_PLP +# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */ +# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */ +# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */ +# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */ +# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */ +# endif /* !INV_EPP_ECP_PLP */ +#endif /* __sgi */ + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * '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 copies; /* Number of copies to print */ + int fd; /* Parallel device */ + 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 == 1) + { + list_devices(); + return (0); + } + else 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; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * 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... + */ + + while (copies > 0) + { + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + 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); +} + + +/* + * 'list_devices()' - List all parallel devices. + */ + +void +list_devices(void) +{ + static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz"; + /* Funky hex numbering used for some devices */ + +#ifdef __linux + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + FILE *probe; /* /proc/parport/n/autoprobe file */ + char line[1024], /* Line from file */ + *delim, /* Delimiter in file */ + make[IPP_MAX_NAME], /* Make from file */ + model[IPP_MAX_NAME]; /* Model from file */ + + + for (i = 0; i < 4; i ++) + { + sprintf(device, "/proc/parport/%d/autoprobe", i); + if ((probe = fopen(device, "r")) != NULL) + { + memset(make, 0, sizeof(make)); + memset(model, 0, sizeof(model)); + strcpy(model, "Unknown"); + + while (fgets(line, sizeof(line), probe) != NULL) + { + /* + * Strip trailing ; and/or newline. + */ + + if ((delim = strrchr(line, ';')) != NULL) + *delim = '\0'; + else if ((delim = strrchr(line, '\n')) != NULL) + *delim = '\0'; + + /* + * Look for MODEL and MANUFACTURER lines... + */ + + if (strncmp(line, "MODEL:", 6) == 0 && + strncmp(line, "MODEL:Unknown", 13) != 0) + strncpy(model, line + 6, sizeof(model) - 1); + else if (strncmp(line, "MANUFACTURER:", 13) == 0 && + strncmp(line, "MANUFACTURER:Unknown", 20) != 0) + strncpy(make, line + 13, sizeof(make) - 1); + } + + fclose(probe); + + if (make[0]) + printf("direct parallel:/dev/lp%d \"%s %s\" \"Parallel Port #%d\"\n", + i, make, model, i + 1); + else + printf("direct parallel:/dev/lp%d \"%s\" \"Parallel Port #%d\"\n", + i, model, i + 1); + } + else + { + sprintf(device, "/dev/lp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + else + { + sprintf(device, "/dev/par%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + } + } + } +#elif defined(__sgi) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + inventory_t *inv; /* Hardware inventory info */ + + + /* + * IRIX maintains a hardware inventory of most devices... + */ + + setinvent(); + + while ((inv = getinvent()) != NULL) + { + if (inv->inv_class == INV_PARALLEL && + (inv->inv_type == INV_ONBOARD_PLP || + inv->inv_type == INV_EPP_ECP_PLP)) + { + /* + * Standard parallel port... + */ + + puts("direct parallel:/dev/plp \"Unknown\" \"Onboard Parallel Port\""); + } + else if (inv->inv_class == INV_PARALLEL && + inv->inv_type == INV_EPC_PLP) + { + /* + * EPC parallel port... + */ + + printf("direct parallel:/dev/plp%d \"Unknown\" \"Integral EPC parallel port, Ebus slot %d\"\n", + inv->inv_controller, inv->inv_controller); + } + } + + endinvent(); + + /* + * Central Data makes serial and parallel "servers" that can be + * connected in a number of ways. Look for ports... + */ + + for (i = 0; i < 10; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/lpn%d%c", j, funky_hex[n]); + else if (i == 9) /* PCI */ + sprintf(device, "/dev/lpp%d%c", j, funky_hex[n]); + else /* SCSI */ + sprintf(device, "/dev/lp%d%d%c", i, j, funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n", + device, j, n); + else if (i == 9) + printf("direct parallel:%s \"Unknown\" \"Central Data PCI Parallel Port, ID %d, port %d\"\n", + device, j, n); + else + printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__sun) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard parallel ports... + */ + + for (i = 0; i < 10; i ++) + { + sprintf(device, "/dev/ecpp%d", i); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"Sun IEEE-1284 Parallel Port #%d\"\n", + device, i + 1); + } + + for (i = 0; i < 10; i ++) + { + sprintf(device, "/dev/bpp%d", i); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"Sun Standard Parallel Port #%d\"\n", + device, i + 1); + } + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/lp%d", i); + + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"PC Parallel Port #%d\"\n", + device, i + 1); + } + + /* + * MAGMA parallel ports... + */ + + for (i = 0; i < 40; i ++) + { + sprintf(device, "/dev/pm%02d", i); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"MAGMA Parallel Board #%d Port #%d\"\n", + device, (i / 10) + 1, (i % 10) + 1); + } + + /* + * Central Data parallel ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/sts/lpN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/sts/lp%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n", + device, j, n); + else + printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__hpux) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard parallel ports... + */ + + if (access("/dev/rlp", 0) == 0) + puts("direct parallel:/dev/rlp \"Unknown\" \"Standard Parallel Port (/dev/rlp)\""); + + for (i = 0; i < 7; i ++) + for (j = 0; j < 7; j ++) + { + sprintf(device, "/dev/c%dt%dd0_lp", i, j); + if (access(device, 0) == 0) + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d,%d\"\n", i, j); + } + + /* + * Central Data parallel ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/lpN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/lp%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("direct parallel:%s \"Unknown\" \"Central Data EtherLite Parallel Port, ID %d, port %d\"\n", + device, j, n); + else + printf("direct parallel:%s \"Unknown\" \"Central Data SCSI Parallel Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__osf__) + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/lp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + } +#elif defined(FreeBSD) || defined(OpenBSD) || defined(NetBSD) + int i; /* Looping var */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 3; i ++) + { + sprintf(device, "/dev/lpt%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct parallel:%s \"Unknown\" \"Parallel Port #%d\"\n", device, i + 1); + } + } +#endif +} + + +/* + * End of "$Id$". + */ diff --git a/backend/serial.c b/backend/serial.c new file mode 100644 index 0000000000..dea59bc3a4 --- /dev/null +++ b/backend/serial.c @@ -0,0 +1,656 @@ +/* + * "$Id$" + * + * Serial port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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__ */ + +#ifdef __sgi +# include +# ifndef INV_EPP_ECP_PLP +# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */ +# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */ +# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */ +# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */ +# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */ +# endif /* !INV_EPP_ECP_PLP */ +#endif /* __sgi */ + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * '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 copies; /* Number of copies to print */ + int fd; /* Parallel device */ + 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 == 1) + { + list_devices(); + return (0); + } + else 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; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * 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 serial port device... + */ + + if ((fd = open(resource, O_WRONLY | O_NOCTTY)) == -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... + */ + + while (copies > 0) + { + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + 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); +} + + +/* + * 'list_devices()' - List all serial devices. + */ + +void +list_devices(void) +{ + static char *funky_hex = "0123456789abcdefghijklmnopqrstuvwxyz"; + /* Funky hex numbering used for some devices */ + +#ifdef __linux + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 4; i ++) + { + sprintf(device, "/dev/ttyS%d", i); + if ((fd = open(device, O_WRONLY | O_NOCTTY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } + } +#elif defined(__sgi) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + inventory_t *inv; /* Hardware inventory info */ + + + /* + * IRIX maintains a hardware inventory of most devices... + */ + + setinvent(); + + while ((inv = getinvent()) != NULL) + { + if (inv->inv_class == INV_SERIAL) + { + /* + * Some sort of serial port... + */ + + if (inv->inv_type == INV_CDSIO || inv->inv_type == INV_CDSIO_E) + { + /* + * CDSIO port... + */ + + for (n = 0; n < 6; n ++) + printf("serial serial:/dev/ttyd%d?baud=19200 \"Unknown\" \"CDSIO Board %d Serial Port #%d\"\n", + n + 5 + 8 * inv->inv_controller, inv->inv_controller, n + 1); + } + else if (inv->inv_type == INV_EPC_SERIAL) + { + /* + * Everest serial port... + */ + + if (inv->inv_unit == 0) + i = 1; + else + i = 41 + 4 * (int)inv->inv_controller; + + for (n = 0; n < (int)inv->inv_state; n ++) + printf("serial serial:/dev/ttyd%d?baud=19200 \"Unknown\" \"EPC Serial Port %d, Ebus slot %d\"\n", + n + i, n + 1, (int)inv->inv_controller); + } + else if (inv->inv_state > 1) + { + /* + * Standard serial port under IRIX 6.4 and earlier... + */ + + for (n = 0; n < (int)inv->inv_state; n ++) + printf("serial serial:/dev/ttyd%d?baud=19200 \"Unknown\" \"Onboard Serial Port %d\"\n", + n + (int)inv->inv_unit + 1, n + (int)inv->inv_unit + 1); + } + else + { + /* + * Standard serial port under IRIX 6.5 and beyond... + */ + + printf("serial serial:/dev/ttyd%d?baud=115200 \"Unknown\" \"Onboard Serial Port %d\"\n", + (int)inv->inv_controller, (int)inv->inv_controller); + } + } + } + + endinvent(); + + /* + * Central Data makes serial and parallel "servers" that can be + * connected in a number of ways. Look for ports... + */ + + for (i = 0; i < 10; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/ttydn%d%c", j, funky_hex[n]); + else if (i == 9) /* PCI */ + sprintf(device, "/dev/ttydp%d%c", j, funky_hex[n]); + else /* SCSI */ + sprintf(device, "/dev/ttyd%d%d%c", i, j, funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", + device, j, n); + else if (i == 9) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data PCI Serial Port, ID %d, port %d\"\n", + device, j, n); + else + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__sun) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard serial ports... + */ + + for (i = 0; i < 26; i ++) + { + sprintf(device, "/dev/cua/%c", 'a' + i); + if (access(device, 0) == 0) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } + + /* + * MAGMA serial ports... + */ + + for (i = 0; i < 40; i ++) + { + sprintf(device, "/dev/term/%02d", i); + if (access(device, 0) == 0) + printf("serial serial:%s?baud=38400 \"Unknown\" \"MAGMA Serial Board #%d Port #%d\"\n", + device, (i / 10) + 1, (i % 10) + 1); + } + + /* + * Central Data serial ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/sts/ttyN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/sts/tty%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", + device, j, n); + else + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__hpux) + int i, j, n; /* Looping vars */ + char device[255]; /* Device filename */ + + + /* + * Standard serial ports... + */ + + for (i = 0; i < 10; i ++) + { + sprintf(device, "/dev/tty%dp0", i); + if (access(device, 0) == 0) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } + + /* + * Central Data serial ports... + */ + + for (i = 0; i < 9; i ++) + for (j = 0; j < 8; j ++) + for (n = 0; n < 32; n ++) + { + if (i == 8) /* EtherLite */ + sprintf(device, "/dev/ttyN%d%c", j, funky_hex[n]); + else + sprintf(device, "/dev/tty%c%d%c", i + 'C', j, + funky_hex[n]); + + if (access(device, 0) == 0) + { + if (i == 8) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data EtherLite Serial Port, ID %d, port %d\"\n", + device, j, n); + else + printf("serial serial:%s?baud=38400 \"Unknown\" \"Central Data SCSI Serial Port, logical bus %d, ID %d, port %d\"\n", + device, i, j, n); + } + } +#elif defined(__osf__) + int i; /* Looping var */ + char device[255]; /* Device filename */ + + + /* + * Standard serial ports... + */ + + for (i = 0; i < 100; i ++) + { + sprintf(device, "/dev/tty%02d", i); + if (access(device, 0) == 0) + printf("serial serial:%s?baud=38400 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); + } +#elif defined(FreeBSD) || defined(OpenBSD) || defined(NetBSD) + int i, j; /* Looping vars */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + + + /* + * SIO ports... + */ + + for (i = 0; i < 32; i ++) + { + sprintf(device, "/dev/ttyd%c", funky_hex[i]); + if ((fd = open(device, O_WRONLY | O_NOCTTY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Standard Serial Port #%d\"\n", + device, i + 1); + } + } + + /* + * Cyclades ports... + */ + + for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ + for (j = 0; j < 32; j ++) + { + sprintf(device, "/dev/ttyc%d%c", i, funky_hex[j]); + if ((fd = open(device, O_WRONLY | O_NOCTTY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Cyclades #%d Serial Port #%d\"\n", + device, i, j + 1); + } + } + + /* + * Digiboard ports... + */ + + for (i = 0; i < 16; i ++) /* Should be up to 65536 boards... */ + for (j = 0; j < 32; j ++) + { + sprintf(device, "/dev/ttyD%d%c", i, funky_hex[j]); + if ((fd = open(device, O_WRONLY | O_NOCTTY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Digiboard #%d Serial Port #%d\"\n", + device, i, j + 1); + } + } + + /* + * Stallion ports... + */ + + for (i = 0; i < 32; i ++) + { + sprintf(device, "/dev/ttyE%c", funky_hex[i]); + if ((fd = open(device, O_WRONLY | O_NOCTTY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"Stallion Serial Port #%d\"\n", + device, i + 1); + } + } + + /* + * SX ports... + */ + + for (i = 0; i < 128; i ++) + { + sprintf(device, "/dev/ttyA%d", i + 1); + if ((fd = open(device, O_WRONLY | O_NOCTTY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=115200 \"Unknown\" \"SX Serial Port #%d\"\n", + device, i + 1); + } + } +#endif +} + + +/* + * End of "$Id$". + */ diff --git a/backend/socket.c b/backend/socket.c new file mode 100644 index 0000000000..a3b130384b --- /dev/null +++ b/backend/socket.c @@ -0,0 +1,259 @@ +/* + * "$Id$" + * + * AppSocket backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 + +#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 copies; /* Number of copies to print */ + 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 == 1) + { + puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\""); + return (0); + } + else 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; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * 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); + + while (copies > 0) + { + for (;;) + { + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + perror("ERROR: Unable to create socket"); + 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"); + sleep(30); + } + } + else + break; + } + + /* + * Finally, send the print file... + */ + + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + 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... + */ + + close(fd); + } + + /* + * Close the input file and return... + */ + + if (fp != stdin) + fclose(fp); + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/backend/usb.c b/backend/usb.c new file mode 100644 index 0000000000..e9cb85b8a6 --- /dev/null +++ b/backend/usb.c @@ -0,0 +1,302 @@ +/* + * "$Id$" + * + * USB port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 USB port. + * list_devices() - List all USB devices. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +# include +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * 'main()' - Send a file to the specified USB 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 copies; /* Number of copies to print */ + int fd; /* Parallel device */ + 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 == 1) + { + list_devices(); + return (0); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: USB 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; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = fopen(argv[6], "rb")) == NULL) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * 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 USB port device... + */ + + if ((fd = open(resource, O_WRONLY)) == -1) + { + perror("ERROR: Unable to open USB 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... + */ + + while (copies > 0) + { + copies --; + + if (fp != stdin) + { + fputs("PAGE: 1 1\n", stderr); + rewind(fp); + } + + 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); +} + + +/* + * 'list_devices()' - List all USB devices. + */ + +void +list_devices(void) +{ +#ifdef __linux + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255]; /* Device filename */ + FILE *probe; /* /proc/parport/n/autoprobe file */ + char line[1024], /* Line from file */ + *delim, /* Delimiter in file */ + make[IPP_MAX_NAME], /* Make from file */ + model[IPP_MAX_NAME]; /* Model from file */ + + + if ((probe = fopen("/proc/bus/usb/devices", "r")) != NULL) + { + i = 0; + + memset(make, 0, sizeof(make)); + memset(model, 0, sizeof(model)); + + while (fgets(line, sizeof(line), probe) != NULL) + { + /* + * Strip trailing newline. + */ + + if ((delim = strrchr(line, '\n')) != NULL) + *delim = '\0'; + + /* + * See if it is a printer device ("P: ...") + */ + + if (strncmp(line, "S:", 2) == 0) + { + /* + * String attribute... + */ + + if (strncmp(line, "S: Manufacturer=", 17) == 0) + { + strncpy(make, line + 17, sizeof(make) - 1); + if (strcmp(make, "Hewlett-Packard") == 0) + strcpy(make, "HP"); + } + else if (strncmp(line, "S: Product=", 12) == 0) + strncpy(model, line + 12, sizeof(model) - 1); + } + else if (strncmp(line, "I:", 2) == 0 && + strstr(line, "Driver=printer") != NULL && + make[0] && model[0]) + { + /* + * We were processing a printer device; send the info out... + */ + + printf("direct usb:/dev/usb/usblp%d \"%s %s\" \"USB Printer #%d\"\n", + i, make, model, i + 1); + + i ++; + + memset(make, 0, sizeof(make)); + memset(model, 0, sizeof(model)); + } + } + + fclose(probe); + } + else + { + for (i = 0; i < 8; i ++) + { + sprintf(device, "/dev/usb/usblp%d", i); + if ((fd = open(device, O_WRONLY)) >= 0) + { + close(fd); + printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1); + } + } + } +#elif defined(__sgi) +#elif defined(__sun) +#elif defined(__hpux) +#elif defined(__osf) +#elif defined(FreeBSD) || defined(OpenBSD) || defined(NetBSD) +#endif +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/Makefile b/berkeley/Makefile new file mode 100644 index 0000000000..4c4470203d --- /dev/null +++ b/berkeley/Makefile @@ -0,0 +1,95 @@ +# +# "$Id$" +# +# Berkeley commands makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2000 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) $(OBJS) $(TARGETS) + +# +# Install all targets... +# + +install: + -$(MKDIR) $(BINDIR) + $(CP) lpq lpr lprm $(BINDIR) + -$(MKDIR) $(SBINDIR) + $(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..c89b16dd93 --- /dev/null +++ b/berkeley/lpc.c @@ -0,0 +1,466 @@ +/* + * "$Id$" + * + * "lpc" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 */ +{ + 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); + + snprintf(printer_uri, sizeof(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 + { + /* + * Just show the method... + */ + + *strchr(device, ':') = '\0'; + 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..0cce2aa09e --- /dev/null +++ b/berkeley/lpq.c @@ -0,0 +1,488 @@ +/* + * "$Id$" + * + * "lpq" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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); +static void show_printer(http_t *, const 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 */ + 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 (;;) + { + if (dest) + show_printer(http, dest); + + i = show_jobs(http, dest, user, id, longstatus); + + if (i && interval) + { + fflush(stdout); + 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 */ +#ifdef __osf__ + jobpriority, /* job-priority */ +#endif /* __osf__ */ + jobcount, /* Number of jobs */ + jobcopies, /* Number of copies */ + rank; /* Rank of job */ + char resource[1024]; /* Resource string */ + char rankstr[255]; /* Rank string */ + char namestr[1024]; /* Job name 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 + { + snprintf(resource, sizeof(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... + */ + + jobcount = 0; + + if ((response = cupsDoRequest(http, request, "/jobs/")) != NULL) + { + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + fprintf(stderr, "lpq: get-jobs failed: %s\n", + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (0); + } + + 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; +#ifdef __osf__ + jobpriority = 50; +#endif /* __osf__ */ + jobstate = IPP_JOB_PENDING; + jobname = "untitled"; + jobuser = NULL; + jobdest = NULL; + jobcopies = 1; + + 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; + +#ifdef __osf__ + if (strcmp(attr->name, "job-priority") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobpriority = attr->values[0].integer; +#endif /* __osf__ */ + + 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; + + if (strcmp(attr->name, "copies") == 0 && + attr->value_tag == IPP_TAG_INTEGER) + jobcopies = attr->values[0].integer; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (jobdest == NULL || jobid == 0) + { + if (attr == NULL) + break; + else + continue; + } + + /**** TODO - support OSF/1 and Berkeley formats ****/ + if (!longstatus && jobcount == 0) + puts("Rank Owner Job Files Total Size"); + + jobcount ++; + + /* + * Display the job... + */ + + if (jobstate == IPP_JOB_PROCESSING) + strcpy(rankstr, "active"); + else + { + sprintf(rankstr, "%d%s\t", rank, ranks[rank % 10]); + rank ++; + } + + if (longstatus) + { + puts(""); + + if (jobcopies > 1) + sprintf(namestr, "%d copies of %s", jobcopies, jobname); + else + strcpy(namestr, jobname); + + printf("%s: %-31s [job %d localhost]\n", jobuser, rankstr, jobid); + printf(" %-31.31s %d bytes\n", namestr, jobsize); + } + else + printf("%-6s %-10.10s %-15d %-27.27s %d bytes\n", rankstr, jobuser, + jobid, jobname, jobsize); + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + fprintf(stderr, "lpq: get-jobs failed: %s\n", ippErrorString(cupsLastError())); + return (0); + } + + if (jobcount == 0) + puts("no entries"); + + return (jobcount); +} + + +/* + * 'show_printer()' - Show printer status. + */ + +static void +show_printer(http_t *http, /* I - HTTP connection to server */ + const char *dest) /* I - Destination */ +{ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + ipp_pstate_t state; /* Printer state */ + char uri[HTTP_MAX_URI]; + /* Printer URI */ + + + if (http == NULL) + return; + + /* + * Build an 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; + + 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(uri, "ipp://localhost/printers/%s", dest); + 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, "/")) != NULL) + { + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + fprintf(stderr, "lpq: get-printer-attributes failed: %s\n", + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return; + } + + if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) + state = (ipp_pstate_t)attr->values[0].integer; + else + state = IPP_PRINTER_STOPPED; + + switch (state) + { + case IPP_PRINTER_IDLE : + printf("%s is ready\n", dest); + break; + case IPP_PRINTER_PROCESSING : + printf("%s is ready and printing\n", dest); + break; + case IPP_PRINTER_STOPPED : + printf("%s is not ready\n", dest); + break; + } + + ippDelete(response); + } + else + fprintf(stderr, "lpq: get-printer-attributes failed: %s\n", + ippErrorString(cupsLastError())); +} + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lpr.c b/berkeley/lpr.c new file mode 100644 index 0000000000..554df26f57 --- /dev/null +++ b/berkeley/lpr.c @@ -0,0 +1,315 @@ +/* + * "$Id$" + * + * "lpr" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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. + * sighandler() - Signal catcher for when we print from stdin... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + + +#ifndef WIN32 +# include + + +/* + * Local functions. + */ + +void sighandler(int); +#endif /* !WIN32 */ + + +/* + * Globals... + */ + +char tempfile[1024]; /* Temporary file for printing from stdin */ + + +/* + * '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 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 deletefile; /* Delete file after print? */ + char buffer[8192]; /* Copy buffer */ + FILE *temp; /* Temporary file pointer */ +#ifdef HAVE_SIGACTION + struct sigaction action; /* Signal action */ +#endif /* HAVE_SIGACTION */ + + + 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\' - %s.\n", + argv[i], ippErrorString(cupsLastError())); + 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); + } + +#ifndef WIN32 +# if defined(HAVE_SIGSET) + sigset(SIGHUP, sighandler); + sigset(SIGINT, sighandler); + sigset(SIGTERM, sighandler); +# elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = sighandler; + + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); +# else + signal(SIGHUP, sighandler); + signal(SIGINT, sighandler); + signal(SIGTERM, sighandler); +# endif +#endif /* !WIN32 */ + + 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) + { + fprintf(stderr, "lpr: unable to print standard input - %s.\n", + ippErrorString(cupsLastError())); + return (1); + } + } + + return (0); +} + + +#ifndef WIN32 +/* + * 'sighandler()' - Signal catcher for when we print from stdin... + */ + +void +sighandler(int s) /* I - Signal number */ +{ + /* + * Remove the temporary file we're using to print from stdin... + */ + + unlink(tempfile); + + /* + * Exit... + */ + + exit(s); +} +#endif /* !WIN32 */ + + +/* + * End of "$Id$". + */ diff --git a/berkeley/lprm.c b/berkeley/lprm.c new file mode 100644 index 0000000000..4b931a683b --- /dev/null +++ b/berkeley/lprm.c @@ -0,0 +1,221 @@ +/* + * "$Id$" + * + * "lprm" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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; + http = 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) + { + snprintf(uri, sizeof(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); + } + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser()); + + /* + * 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) + { + switch (response->request.status.status_code) + { + case IPP_NOT_FOUND : + fputs("lprm: Job or printer not found!\n", stderr); + break; + case IPP_NOT_AUTHORIZED : + fputs("lprm: Not authorized to lprm job(s)!\n", stderr); + break; + case IPP_FORBIDDEN : + fprintf(stderr, "lprm: You don't own job ID %d!\n", job_id); + break; + default : + if (response->request.status.status_code > IPP_OK_CONFLICT) + fputs("lprm: Unable to lprm job(s)!\n", stderr); + break; + } + + 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..5c363c36e1 --- /dev/null +++ b/cgi-bin/Makefile @@ -0,0 +1,117 @@ +# +# "$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 = admin.cgi classes.cgi jobs.cgi printers.cgi +LIBOBJS = abort.o email.o html.o ipp-var.o template.o var.o +OBJS = $(LIBOBJS) admin.o classes.o jobs.o printers.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) libcgi.a $(TARGETS) + + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERBIN)/cgi-bin + $(CP) $(TARGETS) $(SERVERBIN)/cgi-bin + + +# +# libcgi.a +# + +libcgi.a: $(LIBOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + +$(LIBOBJS): cgi.h +ipp-var.o: ipp-var.h + + +# +# admin.cgi +# + +admin.cgi: admin.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ admin.o libcgi.a $(LIBS) + +admin.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + + +# +# classes.cgi +# + +classes.cgi: classes.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ classes.o libcgi.a $(LIBS) + +classes.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + + +# +# jobs.cgi +# + +jobs.cgi: jobs.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ jobs.o libcgi.a $(LIBS) + +jobs.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + + +# +# printers.cgi +# + +printers.cgi: printers.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ printers.o libcgi.a $(LIBS) + +printers.o: cgi.h ipp-var.h ../cups/cups.h ../cups/ipp.h ../cups/language.h + +$(OBJS): ../Makedefs + +# +# End of "$Id$". +# diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c new file mode 100644 index 0000000000..6982b3671a --- /dev/null +++ b/cgi-bin/admin.c @@ -0,0 +1,888 @@ +/* + * "$Id$" + * + * Administration CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 "ipp-var.h" + + +/* + * Local functions... + */ + +static void do_am_class(http_t *http, cups_lang_t *language, int modify); +static void do_am_printer(http_t *http, cups_lang_t *language, int modify); +static void do_delete_class(http_t *http, cups_lang_t *language); +static void do_delete_printer(http_t *http, cups_lang_t *language); +static void do_job_op(http_t *http, cups_lang_t *language, ipp_op_t op); +static void do_printer_op(http_t *http, cups_lang_t *language, ipp_op_t op); +static void do_test_page(http_t *http, cups_lang_t *language); + + +/* + * '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 */ + http_t *http; /* Connection to the server */ + const char *op; /* Operation name */ + + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Send a standard header... + */ + + printf("Content-Type: text/html;charset=%s\n\n", cupsLangEncoding(language)); + + cgiSetVariable("TITLE", "Admin"); + cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME")); + cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER")); + cgiSetVariable("CUPS_VERSION", CUPS_SVERSION); + + cgiCopyTemplateFile(stdout, TEMPLATES "/header.tmpl"); + + /* + * See if we have form data... + */ + + if (!cgiInitialize()) + { + /* + * Nope, send the administration menu... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/admin.tmpl"); + } + else if ((op = cgiGetVariable("OP")) != NULL) + { + /* + * Connect to the HTTP server... + */ + + http = httpConnect("localhost", ippPort()); + + /* + * Do the operation... + */ + + if (strcmp(op, "cancel-job") == 0) + do_job_op(http, language, IPP_CANCEL_JOB); + else if (strcmp(op, "hold-job") == 0) + do_job_op(http, language, IPP_HOLD_JOB); + else if (strcmp(op, "release-job") == 0) + do_job_op(http, language, IPP_RELEASE_JOB); + else if (strcmp(op, "restart-job") == 0) + do_job_op(http, language, IPP_RESTART_JOB); + else if (strcmp(op, "start-printer") == 0) + do_printer_op(http, language, IPP_RESUME_PRINTER); + else if (strcmp(op, "stop-printer") == 0) + do_printer_op(http, language, IPP_PAUSE_PRINTER); + else if (strcmp(op, "accept-jobs") == 0) + do_printer_op(http, language, CUPS_ACCEPT_JOBS); + else if (strcmp(op, "reject-jobs") == 0) + do_printer_op(http, language, CUPS_REJECT_JOBS); + else if (strcmp(op, "print-test-page") == 0) + do_test_page(http, language); + else if (strcmp(op, "add-class") == 0) + do_am_class(http, language, 0); + else if (strcmp(op, "add-printer") == 0) + do_am_printer(http, language, 0); + else if (strcmp(op, "modify-class") == 0) + do_am_class(http, language, 1); + else if (strcmp(op, "modify-printer") == 0) + do_am_printer(http, language, 1); + else if (strcmp(op, "delete-class") == 0) + do_delete_class(http, language); + else if (strcmp(op, "delete-printer") == 0) + do_delete_printer(http, language); + else + { + /* + * Bad operation code... Display an error... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/admin-op.tmpl"); + } + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + } + else + { + /* + * Form data but no operation code... Display an error... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/admin-op.tmpl"); + } + + /* + * Send the standard trailer... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/trailer.tmpl"); + + /* + * Free the request language... + */ + + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'do_am_class()' - Add or modify a class. + */ + +static void +do_am_class(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + int modify) /* I - Modify the printer? */ +{ +} + + +/* + * 'do_am_printer()' - Add or modify a printer. + */ + +static void +do_am_printer(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + int modify) /* I - Modify the printer? */ +{ + int i; /* Looping var */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_status_t status; /* Request status */ + const char *var; /* CGI variable */ + char uri[HTTP_MAX_URI], /* Device or printer URI */ + *uriptr; /* Pointer into URI */ + int maxrate; /* Maximum baud rate */ + char baudrate[255]; /* Baud rate string */ + static int baudrates[] = /* Baud rates */ + { + 1200, + 2400, + 4800, + 9600, + 19200, + 38400, + 57600, + 115200, + 230400, + 460800 + }; + + + if (cgiGetVariable("PRINTER_LOCATION") == NULL) + { + if (modify) + { + /* + * Build an 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); + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", + cgiGetVariable("PRINTER_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, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + } + + /* + * Update the location and description of an existing printer... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/modify-printer.tmpl"); + } + else + { + /* + * Get the name, location, and description for a new printer... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/add-printer.tmpl"); + } + } + else if ((var = cgiGetVariable("DEVICE_URI")) == NULL) + { + /* + * Build a CUPS_GET_DEVICES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_DEVICES; + 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, "printer-uri", + NULL, "ipp://localhost/printers/"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + } + + /* + * Let the user choose... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/choose-device.tmpl"); + } + else if (strchr(var, '/') == NULL) + { + /* + * User needs to set the full URI... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/choose-uri.tmpl"); + } + else if (strncmp(var, "serial:", 7) == 0 && cgiGetVariable("BAUDRATE") == NULL) + { + /* + * Need baud rate, parity, etc. + */ + + if ((var = strchr(var, '?')) != NULL && + strncmp(var, "?baud=", 6) == 0) + maxrate = atoi(var + 6); + else + maxrate = 19200; + + for (i = 0; i < 10; i ++) + if (baudrates[i] > maxrate) + break; + else + { + sprintf(baudrate, "%d", baudrates[i]); + cgiSetArray("BAUDRATES", i, baudrate); + } + + cgiCopyTemplateFile(stdout, TEMPLATES "/choose-serial.tmpl"); + } + else if ((var = cgiGetVariable("PPD_NAME")) == NULL) + { + /* + * Build a CUPS_GET_PPDS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_GET_PPDS; + 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, "printer-uri", + NULL, "ipp://localhost/printers/"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + } + + /* + * Let the user choose... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/choose-model.tmpl"); + } + else + { + /* + * Build a CUPS_ADD_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * printer-location + * printer-info + * ppd-name + * device-uri + * printer-is-accepting-jobs + * printer-state + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_ADD_PRINTER; + 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); + + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", + cgiGetVariable("PRINTER_NAME")); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", + NULL, cgiGetVariable("PRINTER_LOCATION")); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", + NULL, cgiGetVariable("PRINTER_INFO")); + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", + NULL, cgiGetVariable("PPD_NAME")); + + strcpy(uri, cgiGetVariable("DEVICE_URI")); + if (strncmp(uri, "serial:", 7) == 0) + { + /* + * Update serial port URI to include baud rate, etc. + */ + + if ((uriptr = strchr(uri, '?')) == NULL) + uriptr = uri + strlen(uri); + + sprintf(uriptr, "?baud=%s+bits=%s+parity=%s+flow=%s", + cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"), + cgiGetVariable("PARITY"), cgiGetVariable("FLOW")); + } + + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", + NULL, uri); + + ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); + + ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", + IPP_PRINTER_IDLE); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + ippDelete(response); + } + else + status = IPP_NOT_AUTHORIZED; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + } + else if (modify) + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-modified.tmpl"); + else + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-added.tmpl"); + } +} + + +/* + * 'do_delete_class()' - Delete a class... + */ + +static void +do_delete_class(http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *pclass; /* Printer class name */ + ipp_status_t status; /* Operation status... */ + + + if (cgiGetVariable("CONFIRM") == NULL) + { + cgiCopyTemplateFile(stdout, TEMPLATES "/class-confirm.tmpl"); + return; + } + + if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/classes/%s", pclass); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + return; + } + + /* + * Build a CUPS_DELETE_CLASS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_DELETE_CLASS; + 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, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + } + else + cgiCopyTemplateFile(stdout, TEMPLATES "/class-deleted.tmpl"); +} + + +/* + * 'do_delete_printer()' - Delete a printer... + */ + +static void +do_delete_printer(http_t *http, /* I - HTTP connection */ + cups_lang_t *language)/* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *printer; /* Printer printer name */ + ipp_status_t status; /* Operation status... */ + + + if (cgiGetVariable("CONFIRM") == NULL) + { + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-confirm.tmpl"); + return; + } + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + return; + } + + /* + * Build a CUPS_DELETE_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = CUPS_DELETE_PRINTER; + 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, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + } + else + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-deleted.tmpl"); +} + + +/* + * 'do_job_op()' - Do a job operation. + */ + +static void +do_job_op(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + ipp_op_t op) /* I - Operation to perform */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *job; /* Job ID */ + const char *printer; /* Printer name (purge-jobs) */ + ipp_status_t status; /* Operation status... */ + + + if ((job = cgiGetVariable("JOB_ID")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%s", job); + else if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + return; + } + + /* + * Build a job request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri or printer-uri (purge-jobs) + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = op; + 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); + + if (job) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", + NULL, uri); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + if (getenv("REMOTE_USER") != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "root"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + } + else if (op == IPP_CANCEL_JOB) + cgiCopyTemplateFile(stdout, TEMPLATES "/job-cancel.tmpl"); + else if (op == IPP_HOLD_JOB) + cgiCopyTemplateFile(stdout, TEMPLATES "/job-hold.tmpl"); + else if (op == IPP_RELEASE_JOB) + cgiCopyTemplateFile(stdout, TEMPLATES "/job-release.tmpl"); +} + + +/* + * 'do_printer_op()' - Do a printer operation. + */ + +static void +do_printer_op(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, /* I - Client's language */ + ipp_op_t op) /* I - Operation to perform */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Printer URI */ + const char *printer; /* Printer name (purge-jobs) */ + ipp_status_t status; /* Operation status... */ + + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + return; + } + + /* + * Build a printer request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + request->request.op.operation_id = op; + 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, "printer-uri", + NULL, uri); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + } + else if (op == IPP_PAUSE_PRINTER) + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-stop.tmpl"); + else if (op == IPP_RESUME_PRINTER) + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-start.tmpl"); + else if (op == CUPS_ACCEPT_JOBS) + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-accept.tmpl"); + else if (op == CUPS_REJECT_JOBS) + cgiCopyTemplateFile(stdout, TEMPLATES "/printer-reject.tmpl"); +} + + +/* + * 'do_test_page()' - Send a test page. + */ + +static void +do_test_page(http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Client's language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *printer; /* Printer name (purge-jobs) */ + ipp_status_t status; /* Operation status... */ + + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + return; + } + + /* + * Build an IPP_PRINT_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name + * document-format + */ + + request = ippNew(); + + request->request.op.operation_id = IPP_PRINT_JOB; + 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, "printer-uri", + NULL, uri); + + if (getenv("REMOTE_USER") != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "root"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", + NULL, "Test Page"); + + ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format", + NULL, "application/postscript"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoFileRequest(http, request, uri + 15, + CUPS_DATADIR "/data/testprint.ps")) != NULL) + { + status = response->request.status.status_code; + ippSetCGIVars(response); + + ippDelete(response); + } + else + status = IPP_GONE; + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateFile(stdout, TEMPLATES "/error.tmpl"); + } + else + cgiCopyTemplateFile(stdout, TEMPLATES "/test-page.tmpl"); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/cgi.h b/cgi-bin/cgi.h new file mode 100644 index 0000000000..2217bc298f --- /dev/null +++ b/cgi-bin/cgi.h @@ -0,0 +1,81 @@ +/* + * "$Id$" + * + * CGI support library definitions. + * + * Copyright 1997-2000 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _CGI_H_ +# define _CGI_H_ + +# include +# include +# include +# include + +# ifdef WIN32 +# include +# include +# include +# define strcasecmp(s,t) stricmp((s),(t)) +# define strncasecmp(s,t,n) strnicmp((s),(t),(n)) +# else +# include +# endif /* WIN32 */ + + +/* + * Prototypes... + */ + +extern int cgiInitialize(void); +extern void cgiAbort(const char *title, const char *stylesheet, + const char *format, ...); +extern int cgiCheckVariables(const char *names); +extern const char *cgiGetArray(const char *name, int element); +extern int cgiGetSize(const char *name); +extern void cgiSetSize(const char *name, int size); +extern const char *cgiGetVariable(const char *name); +extern void cgiSetArray(const char *name, int element, + const char *value); +extern void cgiSetVariable(const char *name, const char *value); +extern void cgiCopyTemplateFile(FILE *out, const char *template); + +extern void cgiStartHTML(FILE *out, const char *author, + const char *stylesheet, + const char *keywords, + const char *description, + const char *title, ...); +extern void cgiEndHTML(FILE *out); + +extern FILE *cgiEMailOpen(const char *from, const char *to, + const char *cc, const char *subject, + int multipart); +extern void cgiEMailPart(FILE *mail, const char *type, + const char *charset, const char *encoding); +extern void cgiEMailClose(FILE *mail); + + +# define cgiGetUser() getenv("REMOTE_USER") +# define cgiGetHost() (getenv("REMOTE_HOST") == NULL ? getenv("REMOTE_ADDR") : getenv("REMOTE_HOST")) + +#endif /* !_CGI_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/classes.c b/cgi-bin/classes.c new file mode 100644 index 0000000000..d0531dfb57 --- /dev/null +++ b/cgi-bin/classes.c @@ -0,0 +1,221 @@ +/* + * "$Id$" + * + * Class status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * '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 *pclass; /* Printer class name */ + http_t *http; /* Connection to the server */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; + /* Printer URI */ + const char *which_jobs; /* Which jobs to show */ + + + /* + * Get any form variables... + */ + + cgiInitialize(); + + /* + * 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... + */ + + pclass = argv[0]; + if (strcmp(pclass, "/") == 0 || strcmp(pclass, "classes.cgi") == 0) + { + pclass = NULL; + cgiSetVariable("TITLE", "Classes"); + } + else + cgiSetVariable("TITLE", pclass); + + /* + * Get the printer info... + */ + + request = ippNew(); + + 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 (pclass == NULL) + { + /* + * Build a CUPS_GET_CLASSES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request->request.op.operation_id = CUPS_GET_CLASSES; + request->request.op.request_id = 1; + } + else + { + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/classes/%s", getenv("SERVER_NAME"), + pclass); + 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, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + } + + /* + * Write the report... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/header.tmpl"); + cgiCopyTemplateFile(stdout, TEMPLATES "/classes.tmpl"); + + /* + * Get jobs for the specified class if a class has been chosen... + */ + + if (pclass != NULL) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + 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); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/classes/%s", getenv("SERVER_NAME"), + pclass); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + + if ((which_jobs = cgiGetVariable("which_jobs")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", + NULL, which_jobs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + + cgiCopyTemplateFile(stdout, TEMPLATES "/jobs.tmpl"); + } + } + + cgiCopyTemplateFile(stdout, TEMPLATES "/trailer.tmpl"); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/html.c b/cgi-bin/html.c new file mode 100644 index 0000000000..c2b47c4c05 --- /dev/null +++ b/cgi-bin/html.c @@ -0,0 +1,89 @@ +/* + * "$Id$" + * + * CGI HTML functions. + * + * Copyright 1997-2000 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contents: + * + * cgiStartHTML() - Start an HTML document stream. + * cgiEndHTML() - End an HTML document stream. + */ + +#include "cgi.h" +#include + + +/* + * 'cgiStartHTML()' - Start an HTML document stream. + */ + +void +cgiStartHTML(FILE *out, /* I - Output file to use */ + const char *stylesheet, /* I - Stylesheet to use */ + const char *author, /* I - Author name */ + const char *keywords, /* I - Search keywords */ + const char *description, /* I - Description of document */ + const char *title, /* I - Title for page */ + ...) /* I - Any addition args for title */ +{ + va_list ap; /* Argument pointer */ + + + fputs("Content-type: text/html\n\n", out); + fputs("\n", out); + fputs("\n", out); + fputs("\n", out); + + fputs("\t\n", out); + va_start(ap, title); + vfprintf(out, title, ap); + va_end(ap); + fputs("\n", out); + + if (stylesheet) + fprintf(out, "\t\n", + stylesheet); + if (author) + fprintf(out, "\t\n", author); + if (keywords) + fprintf(out, "\t\n", keywords); + if (description) + fprintf(out, "\t\n", description); + + fputs("\n", out); + fputs("\n", out); +} + + +/* + * 'cgiEndHTML()' - End an HTML document stream. + */ + +void +cgiEndHTML(FILE *out) /* I - Output file to use */ +{ + fputs("\n", out); + fputs("\n", out); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c new file mode 100644 index 0000000000..3c61f3a0ba --- /dev/null +++ b/cgi-bin/ipp-var.c @@ -0,0 +1,175 @@ +/* + * "$Id$" + * + * IPP variable 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: + * + * ippSetCGIVars() - Set CGI variables from an IPP response. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * 'ippSetCGIVars()' - Set CGI variables from an IPP response. + */ + +void +ippSetCGIVars(ipp_t *response) /* I - Response data to be copied... */ +{ + int element; /* Element in CGI array */ + ipp_attribute_t *attr; /* Attribute in response... */ + int i; /* Looping var */ + char name[1024], /* Name of attribute */ + value[16384], /* Value(s) */ + *valptr; /* Pointer into value */ + char method[HTTP_MAX_URI], + username[HTTP_MAX_URI], + hostname[HTTP_MAX_URI], + resource[HTTP_MAX_URI], + uri[HTTP_MAX_URI]; + int port; + + + cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME")); + cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER")); + cgiSetVariable("CUPS_VERSION", CUPS_SVERSION); + + for (attr = response->attrs; + attr && attr->group_tag == IPP_TAG_OPERATION; + attr = attr->next); + + for (element = 0; attr != NULL; attr = attr->next, element ++) + { + /* + * Copy attributes to a separator... + */ + +/* puts("
");*/ + + for (; attr != NULL && attr->group_tag != IPP_TAG_ZERO; attr = attr->next) + { + /* + * Copy the attribute name, substituting "_" for "-"... + */ + + if (attr->name == NULL) + continue; + +/* printf("

%s\n", attr->name);*/ + + for (i = 0; attr->name[i]; i ++) + if (attr->name[i] == '-') + name[i] = '_'; + else + name[i] = attr->name[i]; + + name[i] = '\0'; + + /* + * Copy values... + */ + + value[0] = '\0'; + valptr = value; + + for (i = 0; i < attr->num_values; i ++) + { + if (i) + strcat(valptr, ","); + + valptr += strlen(valptr); + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + sprintf(valptr, "%d", attr->values[i].integer); + break; + + case IPP_TAG_BOOLEAN : + sprintf(valptr, "%d", attr->values[i].boolean); + break; + + case IPP_TAG_NOVALUE : + strcat(valptr, "novalue"); + break; + + case IPP_TAG_RANGE : + sprintf(valptr, "%d-%d", attr->values[i].range.lower, + attr->values[i].range.upper); + break; + + case IPP_TAG_RESOLUTION : + sprintf(valptr, "%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_URI : + if (strncmp(attr->values[i].string.text, "ipp:", 4) == 0) + { + httpSeparate(attr->values[i].string.text, method, username, + hostname, &port, resource); + if (username[0]) + snprintf(uri, sizeof(uri), "http://%s@%s:%d%s", username, + hostname, port, resource); + else + snprintf(uri, sizeof(uri), "http://%s:%d%s", hostname, port, + resource); + + strcat(valptr, uri); + 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 : + strcat(valptr, attr->values[i].string.text); + break; + } + } + + /* + * Add the element... + */ + + cgiSetArray(name, element, value); + } + + if (attr == NULL) + break; + } +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/ipp-var.h b/cgi-bin/ipp-var.h new file mode 100644 index 0000000000..a657b63344 --- /dev/null +++ b/cgi-bin/ipp-var.h @@ -0,0 +1,54 @@ +/* + * "$Id$" + * + * IPP variable definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 "cgi.h" + + +/* + * Definitions... + */ + +/*#define TEMPLATES "/home/mike/c/cups/templates"*/ +#define TEMPLATES CUPS_DATADIR "/templates" + + +/* + * Prototype... + */ + +extern void ippSetCGIVars(ipp_t *response); + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/jobs.c b/cgi-bin/jobs.c new file mode 100644 index 0000000000..fe90bbef6d --- /dev/null +++ b/cgi-bin/jobs.c @@ -0,0 +1,140 @@ +/* + * "$Id$" + * + * Job status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * '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 */ + http_t *http; /* Connection to the server */ + const char *which_jobs; /* Which jobs to show */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + + + /* + * Get any form variables... + */ + + cgiInitialize(); + + /* + * 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)); + + cgiSetVariable("TITLE", "Jobs"); + cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME")); + cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER")); + cgiSetVariable("CUPS_VERSION", CUPS_SVERSION); + + cgiCopyTemplateFile(stdout, TEMPLATES "/header.tmpl"); + + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + 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); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, + "ipp://localhost/jobs"); + + if ((which_jobs = cgiGetVariable("which_jobs")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", + NULL, which_jobs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + + cgiCopyTemplateFile(stdout, TEMPLATES "/jobs.tmpl"); + } + + cgiCopyTemplateFile(stdout, TEMPLATES "/trailer.tmpl"); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/printers.c b/cgi-bin/printers.c new file mode 100644 index 0000000000..5a6d3c131c --- /dev/null +++ b/cgi-bin/printers.c @@ -0,0 +1,221 @@ +/* + * "$Id$" + * + * Printer status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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. + */ + +/* + * Include necessary headers... + */ + +#include "ipp-var.h" + + +/* + * '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 */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; + /* Printer URI */ + const char *which_jobs; /* Which jobs to show */ + + + /* + * Get any form variables... + */ + + cgiInitialize(); + + /* + * 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; + cgiSetVariable("TITLE", "Printers"); + } + else + cgiSetVariable("TITLE", printer); + + /* + * Get the printer info... + */ + + request = ippNew(); + + 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 (printer == NULL) + { + /* + * Build a CUPS_GET_PRINTERS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + */ + + request->request.op.operation_id = CUPS_GET_PRINTERS; + request->request.op.request_id = 1; + } + else + { + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/printers/%s", getenv("SERVER_NAME"), + printer); + 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, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + } + + /* + * Write the report... + */ + + cgiCopyTemplateFile(stdout, TEMPLATES "/header.tmpl"); + cgiCopyTemplateFile(stdout, TEMPLATES "/printers.tmpl"); + + /* + * Get jobs for the specified printer if a printer has been chosen... + */ + + if (printer != NULL) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + 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); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + snprintf(uri, sizeof(uri), "ipp://%s/printers/%s", getenv("SERVER_NAME"), + printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + + if ((which_jobs = cgiGetVariable("which_jobs")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", + NULL, which_jobs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + ippSetCGIVars(response); + ippDelete(response); + + cgiCopyTemplateFile(stdout, TEMPLATES "/jobs.tmpl"); + } + } + + cgiCopyTemplateFile(stdout, TEMPLATES "/trailer.tmpl"); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/template.c b/cgi-bin/template.c new file mode 100644 index 0000000000..4506305eb2 --- /dev/null +++ b/cgi-bin/template.c @@ -0,0 +1,364 @@ +/* + * "$Id$" + * + * CGI template function. + * + * Copyright 1997-2000 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contents: + * + * cgiCopyTemplateFile() - Copy a template file and replace all the + * '{variable}' strings with the variable value. + * cgi_copy() - Copy the template file, substituting as needed... + * cgi_puts() - Put a string to the output file, quoting as + * needed... + */ + +#include "cgi.h" + + +/* + * Local functions... + */ + +static void cgi_copy(FILE *out, FILE *in, int element, char term); +static void cgi_puts(const char *s, FILE *out); + + +/* + * 'cgiCopyTemplateFile()' - Copy a template file and replace all the + * '{variable}' strings with the variable value. + */ + +void +cgiCopyTemplateFile(FILE *out, /* I - Output file */ + const char *template) /* I - Template file to read */ +{ + FILE *in; /* Input file */ + + + /* + * Open the template file... + */ + + if ((in = fopen(template, "r")) == NULL) + return; + + /* + * Parse the file to the end... + */ + + cgi_copy(out, in, 0, 0); + + /* + * Close the template file and return... + */ + + fclose(in); +} + + +/* + * 'cgi_copy()' - Copy the template file, substituting as needed... + */ + +static void +cgi_copy(FILE *out, /* I - Output file */ + FILE *in, /* I - Input file */ + int element, /* I - Element number (0 to N) */ + char term) /* I - Terminating character */ +{ + int ch; /* Character from file */ + char op; /* Operation */ + char name[255], /* Name of variable */ + innername[255], /* Inner comparison name */ + *innerptr, /* Pointer into inner name */ + *s; /* String pointer */ + const char *value; /* Value of variable */ + const char *innerval; /* Inner value */ + char outval[1024], /* Output string */ + compare[1024]; /* Comparison string */ + int result; /* Result of comparison */ + + + /* + * Parse the file to the end... + */ + + while ((ch = getc(in)) != EOF) + if (ch == term) + break; + else if (ch == '{') + { + /* + * Get a variable name... + */ + + for (s = name; (ch = getc(in)) != EOF;) + if (strchr("}]<>=!", ch)) + break; + else if (s > name && ch == '?') + break; + else + *s++ = ch; + + *s = '\0'; + + /* + * See if it has a value... + */ + + if (name[0] == '?') + { + /* + * Insert value only if it exists... + */ + + if ((value = cgiGetArray(name + 1, element)) != NULL) + strcpy(outval, value); + else + outval[0] = '\0'; + } + else if (name[0] == '#') + { + /* + * Insert count... + */ + + if (name[1]) + sprintf(outval, "%d", cgiGetSize(name + 1)); + else + sprintf(outval, "%d", element + 1); + } + else if (name[0] == '[') + { + /* + * Loop for # of elements... + */ + + int i; /* Looping var */ + long pos; /* File position */ + int count; /* Number of elements */ + + + if (isdigit(name[1])) + count = atoi(name + 1); + else + count = cgiGetSize(name + 1); + + pos = ftell(in); + + if (count > 0) + { + for (i = 0; i < count; i ++) + { + fseek(in, pos, SEEK_SET); + cgi_copy(out, in, i, '}'); + } + } + else + cgi_copy(NULL, in, 0, '}'); + + continue; + } + else + { + /* + * Insert variable or variable name (if element is NULL)... + */ + + if ((value = cgiGetArray(name, element)) == NULL) + sprintf(outval, "{%s}", name); + else + strcpy(outval, value); + } + + /* + * See if the terminating character requires another test... + */ + + if (ch == '}') + { + /* + * End of substitution... + */ + + if (out) + cgi_puts(outval, out); + + continue; + } + + /* + * OK, process one of the following checks: + * + * {name?exist:not-exist} Exists? + * {name=value?true:false} Equal + * {namevalue?true:false} Greater than + * {name!value?true:false} Not equal + */ + + if (ch == '?') + { + /* + * Test for existance... + */ + + result = cgiGetArray(name, element) != NULL && outval[0]; + } + else + { + /* + * Compare to a string... + */ + + op = ch; + + for (s = compare; (ch = getc(in)) != EOF;) + if (ch == '?') + break; + else if (ch == '#') + { + sprintf(s, "%d", element + 1); + s += strlen(s); + } + else if (ch == '{') + { + /* + * Grab the value of a variable... + */ + + innerptr = innername; + while ((ch = getc(in)) != EOF && ch != '}') + *innerptr++ = ch; + *innerptr = '\0'; + + if (innername[0] == '#') + sprintf(s, "%d", cgiGetSize(innername + 1)); + else if ((innerptr = strrchr(innername, '-')) != NULL && + isdigit(innerptr[1])) + { + *innerptr++ = '\0'; + if ((innerval = cgiGetArray(innername, atoi(innerptr))) == NULL) + *s = '\0'; + else + strcpy(s, innerval); + } + else if (innername[0] == '?') + { + if ((innerval = cgiGetArray(innername + 1, element)) == NULL) + *s = '\0'; + else + strcpy(s, innerval); + } + else if ((innerval = cgiGetArray(innername, element)) == NULL) + sprintf(s, "{%s}", innername); + else + strcpy(s, innerval); + + s += strlen(s); + } + else if (ch == '\\') + *s++ = getc(in); + else + *s++ = ch; + + *s = '\0'; + + if (ch != '?') + return; + + /* + * Do the comparison... + */ + + switch (op) + { + case '<' : + result = strcasecmp(outval, compare) < 0; + break; + case '>' : + result = strcasecmp(outval, compare) > 0; + break; + case '=' : + result = strcasecmp(outval, compare) == 0; + break; + case '!' : + result = strcasecmp(outval, compare) != 0; + break; + } + } + + if (result) + { + /* + * Comparison true; output first part and ignore second... + */ + + cgi_copy(out, in, element, ':'); + cgi_copy(NULL, in, element, '}'); + } + else + { + /* + * Comparison false; ignore first part and output second... + */ + + cgi_copy(NULL, in, element, ':'); + cgi_copy(out, in, element, '}'); + } + } + else if (ch == '\\') /* Quoted char */ + { + if (out) + putc(getc(in), out); + else + getc(in); + } + else if (out) + putc(ch, out); +} + + +/* + * 'cgi_puts()' - Put a string to the output file, quoting as needed... + */ + +static void +cgi_puts(const char *s, + FILE *out) +{ + while (*s) + { + if (s[0] == '<' && s[1] != '/' && !isalpha(s[1])) + fputs("<", out); + else if (*s == '\"') + fputs(""", out); + else if (s[0] == '&' && isspace(s[1])) + fputs("&", out); + else + putc(*s, out); + + s ++; + } +} + + +/* + * End of "$Id$". + */ diff --git a/cgi-bin/var.c b/cgi-bin/var.c new file mode 100644 index 0000000000..e3607d0bf5 --- /dev/null +++ b/cgi-bin/var.c @@ -0,0 +1,654 @@ +/* + * "$Id$" + * + * CGI form variable and array functions. + * + * Copyright 1997-2000 by Easy Software Products. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Contents: + * + * cgiInitialize() - Initialize the CGI variable "database"... + * cgiCheckVariables() - Check for the presence of "required" variables. + * cgiGetArray() - Get an element from a form array... + * cgiGetSize() - Get the size of a form array value. + * cgiGetVariable() - Get a CGI variable from the database... + * cgiSetArray() - Set array element N to the specified string. + * cgiSetVariable() - Set a CGI variable in the database... + * cgi_add_variable() - Add a form variable. + * cgi_compare_variables() - Compare two variables. + * cgi_find_variable() - Find a variable... + * cgi_initialize_get() - Initialize form variables using the GET method. + * cgi_initialize_post() - Initialize variables using the POST method. + * cgi_initialize_string() - Initialize form variables from a string. + * cgi_sort_variables() - Sort all form variables for faster lookup. + */ + +/*#define DEBUG*/ +#include "cgi.h" + + +/* + * Data structure to hold all the CGI form variables and arrays... + */ + +typedef struct +{ + const char *name; /* Name of variable */ + int nvalues, /* Number of values */ + avalues; /* Number of values allocated */ + const char **values; /* Value(s) of variable */ +} var_t; + + +/* + * Local globals... + */ + +static int form_count = 0, /* Form variable count */ + form_alloc = 0; /* Number of variables allocated */ +static var_t *form_vars = NULL; /* Form variables */ + + +/* + * Local functions... + */ + +static void cgi_add_variable(const char *name, int element, + const char *value); +static int cgi_compare_variables(const var_t *v1, const var_t *v2); +static var_t *cgi_find_variable(const char *name); +static int cgi_initialize_get(void); +static int cgi_initialize_post(void); +static int cgi_initialize_string(const char *data); +static void cgi_sort_variables(void); + + +/* + * 'cgiInitialize()' - Initialize the CGI variable "database"... + */ + +int /* O - Non-zero if there was form data */ +cgiInitialize(void) +{ + char *method; /* Form posting method */ + + +#ifdef DEBUG + setbuf(stdout, NULL); + puts("Content-type: text/plain\n"); +#endif /* DEBUG */ + + method = getenv("REQUEST_METHOD"); + + if (method == NULL) + return (0); + + if (strcasecmp(method, "GET") == 0) + return (cgi_initialize_get()); + else if (strcasecmp(method, "POST") == 0) + return (cgi_initialize_post()); + else + return (0); +} + + +/* + * 'cgiCheckVariables()' - Check for the presence of "required" variables. + * + * Names may be separated by spaces and/or commas. + */ + +int /* O - 1 if all variables present, 0 otherwise */ +cgiCheckVariables(const char *names) /* I - Variables to look for */ +{ + char name[255], /* Current variable name */ + *s; /* Pointer in string */ + const char *val; /* Value of variable */ + int element; /* Array element number */ + + + if (names == NULL) + return (1); + + while (*names != '\0') + { + while (*names == ' ' || *names == ',') + names ++; + + for (s = name; *names != '\0' && *names != ' ' && *names != ','; s ++, names ++) + *s = *names; + + *s = 0; + if (name[0] == '\0') + break; + + if ((s = strrchr(name, '-')) != NULL) + { + *s = '\0'; + element = atoi(s + 1) - 1; + val = cgiGetArray(name, element); + } + else + val = cgiGetVariable(name); + + if (val == NULL) + return (0); + + if (*val == '\0') + return (0); /* Can't be blank, either! */ + } + + return (1); +} + + +/* + * 'cgiGetArray()' - Get an element from a form array... + */ + +const char * /* O - Element value or NULL */ +cgiGetArray(const char *name, /* I - Name of array variable */ + int element) /* I - Element number (0 to N) */ +{ + var_t *var; /* Pointer to variable */ + + + if ((var = cgi_find_variable(name)) == NULL) + return (NULL); + + if (var->nvalues == 1) + return (var->values[0]); + + if (element < 0 || element >= var->nvalues) + return (NULL); + + return (var->values[element]); +} + + +/* + * 'cgiGetSize()' - Get the size of a form array value. + */ + +int /* O - Number of elements */ +cgiGetSize(const char *name) /* I - Name of variable */ +{ + var_t *var; /* Pointer to variable */ + + + if ((var = cgi_find_variable(name)) == NULL) + return (0); + + return (var->nvalues); +} + + +/* + * 'cgiGetVariable()' - Get a CGI variable from the database... + * + * Returns NULL if the variable doesn't exist... If the variable is an + * array of values, returns the last element... + */ + +const char * /* O - Value of variable */ +cgiGetVariable(const char *name)/* I - Name of variable */ +{ + const var_t *var; /* Returned variable */ + + + var = cgi_find_variable(name); + +#ifdef DEBUG + if (var == NULL) + printf("cgiGetVariable(\"%s\") is returning NULL...\n", name); + else + printf("cgiGetVariable(\"%s\") is returning \"%s\"...\n", name, + var->values[var->nvalues - 1]); +#endif /* DEBUG */ + + return ((var == NULL) ? NULL : var->values[var->nvalues - 1]); +} + + +/* + * 'cgiSetArray()' - Set array element N to the specified string. + * + * If the variable array is smaller than (element + 1), the intervening + * elements are set to NULL. + */ + +void +cgiSetArray(const char *name, /* I - Name of variable */ + int element, /* I - Element number (0 to N) */ + const char *value) /* I - Value of variable */ +{ + int i; /* Looping var */ + var_t *var; /* Returned variable */ + + + if (name == NULL || value == NULL || element < 0) + return; + + if ((var = cgi_find_variable(name)) == NULL) + { + cgi_add_variable(name, element, value); + cgi_sort_variables(); + } + else + { + if (element >= var->avalues) + { + var->avalues = element + 16; + var->values = (const char **)realloc((void *)(var->values), + sizeof(char *) * var->avalues); + } + + if (element >= var->nvalues) + { + for (i = var->nvalues; i < element; i ++) + var->values[i] = NULL; + + var->nvalues = element + 1; + } + else if (var->values[element]) + free((char *)var->values[element]); + + var->values[element] = strdup(value); + } +} + + +/* + * 'cgiSetSize()' - Set the array size. + */ + +void +cgiSetSize(const char *name, /* I - Name of variable */ + int size) /* I - Number of elements (0 to N) */ +{ + int i; /* Looping var */ + var_t *var; /* Returned variable */ + + + if (name == NULL || size < 0) + return; + + if ((var = cgi_find_variable(name)) == NULL) + return; + + if (size >= var->avalues) + { + var->avalues = size + 16; + var->values = (const char **)realloc((void *)(var->values), + sizeof(char *) * var->avalues); + } + + if (size > var->nvalues) + { + for (i = var->nvalues; i < size; i ++) + var->values[i] = NULL; + } + else if (size < var->nvalues) + { + for (i = size; i < var->nvalues; i ++) + if (var->values[i]) + free((void *)(var->values[i])); + } + + var->nvalues = size; +} + + +/* + * 'cgiSetVariable()' - Set a CGI variable in the database... + * + * If the variable is an array, this truncates the array to a single element. + */ + +void +cgiSetVariable(const char *name, /* I - Name of variable */ + const char *value) /* I - Value of variable */ +{ + int i; /* Looping var */ + var_t *var; /* Returned variable */ + + + if (name == NULL || value == NULL) + return; + + if ((var = cgi_find_variable(name)) == NULL) + { + cgi_add_variable(name, 0, value); + cgi_sort_variables(); + } + else + { + for (i = 0; i < var->nvalues; i ++) + if (var->values[i]) + free((char *)var->values[i]); + + var->values[0] = strdup(value); + var->nvalues = 1; + } +} + + +/* + * 'cgi_add_variable()' - Add a form variable. + */ + +static void +cgi_add_variable(const char *name, /* I - Variable name */ + int element, /* I - Array element number */ + const char *value) /* I - Variable value */ +{ + var_t *var; /* New variable */ + + + if (name == NULL || value == NULL) + return; + +#ifdef DEBUG + printf("Adding variable \'%s\' with value \'%s\'...\n", name, value); +#endif /* DEBUG */ + + if (form_count >= form_alloc) + { + if (form_alloc == 0) + form_vars = malloc(sizeof(var_t) * 16); + else + form_vars = realloc(form_vars, (form_alloc + 16) * sizeof(var_t)); + + form_alloc += 16; + } + + var = form_vars + form_count; + var->name = strdup(name); + var->nvalues = element + 1; + var->avalues = element + 1; + var->values = calloc(element + 1, sizeof(char *)); + var->values[element] = strdup(value); + + form_count ++; +} + + +/* + * 'cgi_compare_variables()' - Compare two variables. + */ + +static int /* O - Result of comparison */ +cgi_compare_variables(const var_t *v1, /* I - First variable */ + const var_t *v2) /* I - Second variable */ +{ + return (strcasecmp(v1->name, v2->name)); +} + + +/* + * 'cgi_find_variable()' - Find a variable... + */ + +static var_t * /* O - Variable pointer or NULL */ +cgi_find_variable(const char *name) /* I - Name of variable */ +{ + var_t key; /* Search key */ + + + if (form_count < 1 || name == NULL) + return (NULL); + + key.name = name; + + return ((var_t *)bsearch(&key, form_vars, form_count, sizeof(var_t), + (int (*)(const void *, const void *))cgi_compare_variables)); +} + + +/* + * 'cgi_initialize_get()' - Initialize form variables using the GET method. + */ + +static int /* O - 1 if form data read */ +cgi_initialize_get(void) +{ + char *data; /* Pointer to form data string */ + + +#ifdef DEBUG + puts("Initializing variables using GET method..."); +#endif /* DEBUG */ + + /* + * Check to see if there is anything for us to read... + */ + + data = getenv("QUERY_STRING"); + if (data == NULL || strlen(data) == 0) + return (0); + + /* + * Parse it out and return... + */ + + return (cgi_initialize_string(data)); +} + + +/* + * 'cgi_initialize_post()' - Initialize variables using the POST method. + */ + +static int /* O - 1 if form data was read */ +cgi_initialize_post(void) +{ + char *content_length, /* Length of input data (string) */ + *data; /* Pointer to form data string */ + int length, /* Length of input data */ + nbytes, /* Number of bytes read this read() */ + tbytes, /* Total number of bytes read */ + status; /* Return status */ + + +#ifdef DEBUG + puts("Initializing variables using POST method..."); +#endif /* DEBUG */ + + /* + * Check to see if there is anything for us to read... + */ + + content_length = getenv("CONTENT_LENGTH"); + if (content_length == NULL || atoi(content_length) == 0) + return (0); + + /* + * Get the length of the input stream and allocate a buffer for it... + */ + + length = atoi(content_length); + data = malloc(length + 1); + + /* + * Read the data into the buffer... + */ + + for (tbytes = 0; tbytes < length; tbytes += nbytes) + if ((nbytes = read(0, data + tbytes, length - tbytes)) < 0) + { + free(data); + return (0); + } + + data[length] = '\0'; + + /* + * Parse it out... + */ + + status = cgi_initialize_string(data); + + /* + * Free the data and return... + */ + + free(data); + + return (status); +} + + +/* + * 'cgi_initialize_string()' - Initialize form variables from a string. + */ + +static int +cgi_initialize_string(const char *data) /* I - Form data string */ +{ + int done; /* True if we're done reading a form variable */ + char *s, /* Pointer to current form string */ + ch, /* Temporary character */ + name[255], /* Name of form variable */ + value[65536]; /* Variable value... */ + + + /* + * Check input... + */ + + if (data == NULL) + return (0); + + /* + * Loop until we've read all the form data... + */ + + while (*data != '\0') + { + /* + * Get the variable name... + */ + + for (s = name; *data != '\0'; data ++, s ++) + if (*data == '=') + break; + else + *s = *data; + + *s = '\0'; + if (*data == '=') + data ++; + else + return (0); + + /* + * Read the variable value... + */ + + for (s = value, done = 0; !done && *data != '\0'; data ++, s ++) + switch (*data) + { + case '&' : /* End of data... */ + done = 1; + s --; + break; + + case '+' : /* Escaped space character */ + *s = ' '; + break; + + case '%' : /* Escaped control character */ + /* + * Read the hex code from stdin... + */ + + data ++; + ch = *data - '0'; + if (ch > 9) + ch -= 7; + *s = ch << 4; + + data ++; + ch = *data - '0'; + if (ch > 9) + ch -= 7; + *s |= ch; + break; + + default : /* Other characters come straight through */ + *s = *data; + break; + } + + *s = '\0'; /* nul terminate the string */ + + /* + * Remove trailing whitespace... + */ + + s --; + while (s >= value && *s == ' ') + *s-- = '\0'; + + /* + * Add the string to the variable "database"... + */ + + if ((s = strrchr(name, '-')) != NULL && isdigit(s[1])) + { + *s++ = '\0'; + cgiSetArray(name, atoi(s) - 1, value); + } + else + cgiSetVariable(name, value); + } + + return (1); +} + + +/* + * 'cgi_sort_variables()' - Sort all form variables for faster lookup. + */ + +static void +cgi_sort_variables(void) +{ +#ifdef DEBUG + int i; + + + puts("Sorting variables..."); +#endif /* DEBUG */ + + if (form_count < 2) + return; + + qsort(form_vars, form_count, sizeof(var_t), + (int (*)(const void *, const void *))cgi_compare_variables); + +#ifdef DEBUG + puts("New variable list is:"); + for (i = 0; i < form_count; i ++) + printf("%s = %s\n", form_vars[i].name, form_vars[i].value); +#endif /* DEBUG */ +} + + +/* + * End of "$Id$". + */ diff --git a/conf/Makefile b/conf/Makefile new file mode 100644 index 0000000000..e9e8d6c6a5 --- /dev/null +++ b/conf/Makefile @@ -0,0 +1,74 @@ +# +# "$Id$" +# +# Configuration file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2000 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 client.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) + for file in $(KEEP); do \ + if test -r $(SERVERROOT)/$$file ; then \ + $(CP) $$file $(SERVERROOT)/$$file.N ; \ + else \ + $(CP) $$file $(SERVERROOT) ; \ + fi ; \ + done + for file in $(REPLACE); do \ + if test -r $(SERVERROOT)/$$file ; then \ + $(MV) $(SERVERROOT)/$$file $(SERVERROOT)/$$file.O ; \ + fi ; \ + $(CP) $$file $(SERVERROOT) ; \ + done + if test -r /etc/printcap -a ! -r /etc/printcap.O; then \ + $(CP) /etc/printcap /etc/printcap.O ; \ + fi + +# +# End of "$Id$". +# diff --git a/conf/classes.conf b/conf/classes.conf new file mode 100644 index 0000000000..7d1fc3c489 --- /dev/null +++ b/conf/classes.conf @@ -0,0 +1,95 @@ +# +# "$Id: classes.conf 969 2000-03-10 16:56:46Z mike $" +# +# Sample class configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-2000 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 +# + +######################################################################## +# # +# 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 + +# +# State: sets the initial state of the class. Can be one of the +# following: +# +# Idle - Class is available to print new jobs. +# Stopped - Class is disabled but accepting new jobs. +# + +#State Idle + +# +# StateMessage: sets the printer-state-message attribute for the class. +# + +#StateMessage Class is idle. + +# +# Accepting: is the class accepting jobs? +# +#Accepting Yes +#Accepting No +# + +# +# Printer: adds a printer to the class. +# + +#Printer sample +#Printer sample@host2 +# + +# +# End of "$Id: classes.conf 969 2000-03-10 16:56:46Z mike $". +# diff --git a/conf/client.conf b/conf/client.conf new file mode 100644 index 0000000000..26d45e8d5b --- /dev/null +++ b/conf/client.conf @@ -0,0 +1,50 @@ +# +# "$Id: client.conf 969 2000-03-10 16:56:46Z mike $" +# +# Sample client configuration file for the Common UNIX Printing System +# (CUPS). +# +# Copyright 1997-2000 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 +# + +######################################################################## +# # +# This is the CUPS client configuration file. This file is used to # +# define client-specific parameters, such as the default server or # +# default printer. # +# # +######################################################################## + +# +# ServerName: the hostname of your server. By default CUPS will use the +# hostname of the system. +# + +#ServerName myhost.domain.com + +# +# DefaultPrinter: the default printer (or class) that clients should use. +# + +#DefaultPrinter myprinter +#DefaultPrinter myprinter@host + +# +# End of "$Id: client.conf 969 2000-03-10 16:56:46Z mike $". +# diff --git a/conf/cupsd.conf b/conf/cupsd.conf new file mode 100644 index 0000000000..6353f99d40 --- /dev/null +++ b/conf/cupsd.conf @@ -0,0 +1,482 @@ +# +# "$Id: cupsd.conf 969 2000-03-10 16:56:46Z mike $" +# +# Sample configuration file for the Common UNIX Printing System (CUPS) +# scheduler. +# +# Copyright 1997-2000 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 +# + +######################################################################## +# # +# 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. +# +# To set the default server name used by clients, see the client.conf file. +# + +#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 /etc/cups. +# + +#ServerRoot /etc/cups + +# +# ServerBin: the root directory for the scheduler executables. +# By default /usr/lib/cups. +# + +#ServerBin /usr/lib/cups + +# +# DocumentRoot: the root directory for the HTTP server. +# By default /usr/share/doc/cups. +# + +#DocumentRoot /usr/share/doc/cups + +# +# RequestRoot: the directory where request files are stored. +# By default /var/spool/cups. +# + +#RequestRoot /var/spool/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 +# "/var/log/cups/access_log" +# +# You can also use the special name "syslog" to send the output to the +# syslog file or daemon. +# + +#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" +# +# You can also use the special name "syslog" to send the output to the +# syslog file or daemon. +# + +#ErrorLog /var/log/cups/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" +# +# You can also use the special name "syslog" to send the output to the +# syslog file or daemon. +# + +#PageLog /var/log/cups/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 HTTP requests and 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. +# +# Set this to 0 to disable outgoing broadcasts so your local printers are +# not advertised but you can still see printers on other hosts. +# + +#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 + +# +# BrowseOrder: specifies the order of +# + +#BrowseOrder allow,deny +#BrowseOrder deny,allow + +# +# BrowseAllow: specifies an address mask to allow for incoming browser +# packets. The default is to allow packets from all addresses. +# +# BrowseDeny: specifies an address mask to deny for incoming browser +# packets. The default is to deny packets from no addresses. +# +# Both "BrowseAllow" and "BrowseDeny" 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 hostname/domainname restrictions only work if you have turned hostname +# lookups on! +# + +#BrowseAllow address +#BrowseDeny address + +# +# BrowseRelay: relay browser packets from one address/network to another. +# + +#BrowseRelay source-address destination-address + +# +# BrowsePoll: poll the named server for printers +# + +#BrowsePoll address:port + +# +# 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 utf-8. Note that this can also be overridden in +# HTML documents... +# + +#DefaultCharset utf-8 + +# +# 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 + +# +# PreserveJobHistory: whether or not to preserve the job history after a +# job is completed, cancelled, or stopped. Default is Yes. +# + +#PreserveJobHistory Yes + +# +# PreserveJobFiles: whether or not to preserve the job files after a +# job is completed, cancelled, or stopped. Default is No. +# + +#PreserveJobFiles No + +# +# Printcap: the name of the printcap file. Default is /etc/printcap. +# Leave blank to disable printcap file generation. +# + +#Printcap /etc/printcap + +# +# Access permissions for each directory served by the scheduler. +# Locations are relative to DocumentRoot... +# +# AuthType: the authorization to use: +# +# None - Perform no authentication +# Basic - Perform authentication using the HTTP Basic method. +# Digest - Perform authentication using the HTTP Digest method. +# +# (Note: local certificate authentication can be substituted by +# the client for Basic or Digest) +# +# 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. +# + +## Anonymous access (default) +#AuthType None + +## Require a username and password (Basic authentication) +#AuthType Basic +#AuthClass User + +## Require a username and password (Digest/MD5 authentication) +#AuthType Digest +#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 969 2000-03-10 16:56:46Z 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/printcap b/conf/printcap new file mode 100644 index 0000000000..230c3017d6 --- /dev/null +++ b/conf/printcap @@ -0,0 +1,2 @@ +# This is a dummy printcap file that is automatically generated by the +# CUPS software for old applications that rely on it. diff --git a/conf/printers.conf b/conf/printers.conf new file mode 100644 index 0000000000..280ac7c728 --- /dev/null +++ b/conf/printers.conf @@ -0,0 +1,102 @@ +# +# "$Id: printers.conf 969 2000-03-10 16:56:46Z mike $" +# +# Sample printer configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-2000 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 +# + +######################################################################## +# # +# 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 print new jobs. +# Stopped - Printer is disabled but accepting new jobs. +# + +#State Idle + +# +# StateMessage: sets the printer-state-message attribute for the printer. +# + +#StateMessage Printer is idle. + +# +# Accepting: is the printer accepting jobs? +# +#Accepting Yes +#Accepting No + +# + +# +# End of "$Id: printers.conf 969 2000-03-10 16:56:46Z mike $". +# diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000000..f04cdf1e27 --- /dev/null +++ b/config.h.in @@ -0,0 +1,127 @@ +/* + * "$Id$" + * + * Configuration file for the Common UNIX Printing System (CUPS). + * + * @configure_input@ + * + * Copyright 1997-2000 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.1b2" + +/* + * Where are files stored? + */ + +#define CUPS_LOCALEDIR "/usr/share/locale" +#define CUPS_SERVERROOT "/etc/cups" +#define CUPS_SERVERBIN "/usr/lib/cups" +#define CUPS_DOCROOT "/usr/share/doc/cups" +#define CUPS_REQUESTS "/var/spool/cups" +#define CUPS_LOGDIR "/var/logs/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 PAM stuff? + */ + +#ifndef HAVE_LIBPAM +#define HAVE_LIBPAM 0 +#endif /* !HAVE_LIBPAM */ + +/* + * 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 + +/* + * Do we have the vsyslog() function? + */ + +#undef HAVE_VSYSLOG + +/* + * Do we have the (v)snprintf() functions? + */ + +#undef HAVE_SNPRINTF +#undef HAVE_VSNPRINTF + +/* + * 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..e3981bb0c7 --- /dev/null +++ b/configure.in @@ -0,0 +1,355 @@ +dnl +dnl "$Id$" +dnl +dnl Configuration script for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2000 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/[[^0-9]]//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, [ --enable-shared turn on shared libraries [default=yes]]) +if test "$enable_shared" != "no"; then + case "$uname" in + SunOS* | UNIX_S*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC) -Wl,-h,\$@ -G \$(OPTIM) -o" + ;; + HP-UX*) + LIBCUPS="libcups.sl.2" + LIBCUPSIMAGE="libcupsimage.sl.2" + DSO="ld -b -z +h \$@ -o" + ;; + FreeBSD* | NetBSD* | OpenBSD*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC) -Wl,-soname,\$@ -shared \$(OPTIM) -o" + ;; + OSF1* | Linux*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC) -Wl,-soname,\$@ -shared \$(OPTIM) -o" + ;; + IRIX*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC) -soname \$@ -shared \$(OPTIM) -o" + ;; + *) + echo "Warning: shared libraries may not be supported. Trying -shared" + echo " option with compiler." + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC) -Wl,-soname,\$@ -shared \$(OPTIM) -o" + ;; + esac +else + PICFLAG=0 + LIBCUPS="libcups.a" + LIBCUPSIMAGE="libcupsimage.a" + DSO=":" +fi + +AC_ARG_ENABLE(pam, [ --enable-pam turn on PAM support [default=yes]]) + +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(RM,rm) +AC_PATH_PROG(SED,sed) + +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) +if test "$enable_pam" != "no"; then + AC_CHECK_LIB(dl,dlopen) + AC_CHECK_LIB(pam,pam_start) +fi + +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) + +dnl Save the current libraries since we don't want the image libraries +dnl included with every program... +SAVELIBS="$LIBS" + +dnl Check for image libraries... +LIBJPEG="" +LIBPNG="" +LIBTIFF="" +LIBZ="" + +AC_SUBST(LIBJPEG) +AC_SUBST(LIBPNG) +AC_SUBST(LIBTIFF) +AC_SUBST(LIBZ) + +AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, + AC_DEFINE(HAVE_LIBJPEG) + LIBJPEG="-ljpeg" + LIBS="$LIBS -ljpeg") + +AC_CHECK_LIB(z, deflate, + AC_DEFINE(HAVE_LIBZ) + LIBZ="-lz" + LIBS="$LIBS -lz") + +dnl PNG library uses math library functions... +AC_CHECK_LIB(m, pow) + +AC_CHECK_LIB(png, png_read_info, + AC_DEFINE(HAVE_LIBPNG) + LIBPNG="-lpng") + +AC_CHECK_LIB(tiff, TIFFReadScanline, + AC_DEFINE(HAVE_LIBTIFF) + LIBTIFF="-ltiff") + +dnl Restore original LIBS settings... +LIBS="$SAVELIBS" + +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) +AC_CHECK_FUNCS(snprintf) +AC_CHECK_FUNCS(vsnprintf) + +dnl Checks for vsyslog function. +AC_CHECK_FUNCS(vsyslog) + +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 "$GCC"; then + if test -z "$OPTIM"; then + OPTIM="-O2 -g3" + fi + if test $PICFLAG = 1; then + OPTIM="-fPIC $OPTIM" + fi + OPTIM="-Wall $OPTIM" +else + case $uname in + IRIX*) + if test -z "$OPTIM"; then + OPTIM="-O2 -g3" + fi + if test $uversion -ge 62; then + OPTIM="$OPTIM -n32 -mips3" + fi + OPTIM="-fullwarn $OPTIM" + ;; + HP-UX*) + if test -z "$OPTIM"; then + OPTIM="+O2 -g3" + fi + OPTIM="-Ae $OPTIM" + ;; + SunOS*) + # Solaris + if test -z "$OPTIM"; then + OPTIM="-O -g3" + 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 as needed.. +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="${prefix}/lib32" +fi + +dnl Need special attention for the default location... +if test "$prefix" = "/usr" ; then + CUPS_SERVERROOT="/etc/cups" + CUPS_LOGDIR="/var/log/cups" + CUPS_REQUESTS="/var/spool/cups" + + AC_DEFINE_UNQUOTED(CUPS_SERVERROOT, "$CUPS_SERVERROOT") + AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$CUPS_LOGDIR") + AC_DEFINE_UNQUOTED(CUPS_REQUESTS, "$CUPS_REQUESTS") +else + CUPS_SERVERROOT='${prefix}/etc/cups' + CUPS_LOGDIR='${prefix}/log/cups' + CUPS_REQUESTS='${prefix}/spool/cups' + + AC_DEFINE_UNQUOTED(CUPS_SERVERROOT, "$prefix/etc/cups") + AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$prefix/log/cups") + AC_DEFINE_UNQUOTED(CUPS_REQUESTS, "$prefix/spool/cups") +fi + +CUPS_SERVERBIN='${prefix}/lib/cups' +AC_DEFINE_UNQUOTED(CUPS_SERVERBIN, "$prefix/lib/cups") + +AC_SUBST(CUPS_SERVERROOT) +AC_SUBST(CUPS_SERVERBIN) +AC_SUBST(CUPS_LOGDIR) +AC_SUBST(CUPS_REQUESTS) + +dnl Set the CUPS_LOCALE directory... +case "$uname" in + Linux) + CUPS_LOCALEDIR='${prefix}/share/locale' + AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$prefix/share/locale") + ;; + + OSF1) + CUPS_LOCALEDIR='${prefix}/lib/nls/msg' + AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$prefix/lib/nls/msg") + ;; + + *) + # This is the standard System V location... + CUPS_LOCALEDIR='${prefix}/lib/locale' + AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$prefix/lib/locale") + ;; +esac + +AC_SUBST(CUPS_LOCALEDIR) + +dnl Set the CUPS_DATADIR directory... +CUPS_DATADIR='${datadir}/cups' +AC_DEFINE_UNQUOTED(CUPS_DATADIR, "$prefix/share/cups") +AC_SUBST(CUPS_DATADIR) + +dnl Set the CUPS_DOCDIR directory... +CUPS_DOCDIR='${datadir}/doc/cups' +AC_DEFINE_UNQUOTED(CUPS_DOCDIR, "$prefix/share/doc/cups") +AC_SUBST(CUPS_DOCDIR) + +AC_OUTPUT(Makedefs) + +dnl +dnl End of "$Id$". +dnl diff --git a/cups.dsw b/cups.dsw new file mode 100644 index 0000000000..2fc669868f --- /dev/null +++ b/cups.dsw @@ -0,0 +1,128 @@ +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: "cupsd"=.\scheduler\cupsd.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name cups + End Project Dependency +}}} + +############################################################################### + +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.list b/cups.list new file mode 100644 index 0000000000..e35f025659 --- /dev/null +++ b/cups.list @@ -0,0 +1,426 @@ +# +# "$Id: cups.list 986 2000-03-13 18:56:08Z mike $" +# +# ESP Package Manager (EPM) file list for the Common UNIX Printing +# System (CUPS). +# +# Copyright 1997-2000 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 +# + +%product Common UNIX Printing System +%copyright 1993-2000 by Easy Software Products, All Rights Reserved. +%vendor Easy Software Products +%license LICENSE.txt +%readme README.txt +%version 1.1b2 +%incompat printpro + +%system all +# Server files +f 0500 root sys /usr/sbin/cupsd scheduler/cupsd +f 0555 root sys /usr/lib/cups/backend/ipp backend/ipp +l 0555 root sys /usr/lib/cups/backend/http ipp +f 0555 root sys /usr/lib/cups/backend/lpd backend/lpd +f 0555 root sys /usr/lib/cups/backend/parallel backend/parallel +f 0555 root sys /usr/lib/cups/backend/serial backend/serial +f 0555 root sys /usr/lib/cups/backend/socket backend/socket +f 0555 root sys /usr/lib/cups/backend/usb backend/usb +f 0555 root sys /usr/lib/cups/cgi-bin/admin.cgi cgi-bin/admin.cgi +f 0555 root sys /usr/lib/cups/cgi-bin/classes.cgi cgi-bin/classes.cgi +f 0555 root sys /usr/lib/cups/cgi-bin/jobs.cgi cgi-bin/jobs.cgi +f 0555 root sys /usr/lib/cups/cgi-bin/printers.cgi cgi-bin/printers.cgi +f 0555 root sys /usr/lib/cups/daemon/cups-polld scheduler/cups-polld +f 0555 root sys /usr/lib/cups/filter/pstoraster pstoraster/pstoraster +l 0555 root sys /usr/lib/cups/filter/pdftops pstoraster +f 0555 root sys /usr/lib/cups/filter/imagetops filter/imagetops +f 0555 root sys /usr/lib/cups/filter/pstops filter/pstops +f 0555 root sys /usr/lib/cups/filter/texttops filter/texttops +f 0555 root sys /usr/lib/cups/filter/rastertoepson filter/rastertoepson +f 0555 root sys /usr/lib/cups/filter/rastertohp filter/rastertohp +f 0555 root sys /usr/lib/cups/filter/hpgltops filter/hpgltops +f 0555 root sys /usr/lib/cups/filter/imagetoraster filter/imagetoraster + +# Admin commands +l 0555 root sys /usr/bin/disable /usr/sbin/accept +l 0555 root sys /usr/bin/enable /usr/sbin/accept +l 0555 root sys /usr/lib/accept /usr/sbin/accept +l 0555 root sys /usr/lib/lpadmin /usr/sbin/lpadmin +l 0555 root sys /usr/lib/reject accept +f 0555 root sys /usr/sbin/accept systemv/accept +f 0555 root sys /usr/sbin/lpadmin systemv/lpadmin +f 0555 root sys /usr/sbin/lpc berkeley/lpc +l 0555 root sys /usr/sbin/reject accept + +# User commands +f 0555 root sys /usr/bin/cancel systemv/cancel +f 0555 root sys /usr/bin/lp systemv/lp +f 0555 root sys /usr/bin/lpoptions systemv/lpoptions +f 4555 root sys /usr/bin/lppasswd systemv/lppasswd +f 0555 root sys /usr/bin/lpq berkeley/lpq +f 0555 root sys /usr/bin/lpr berkeley/lpr +f 0555 root sys /usr/bin/lprm berkeley/lprm +f 0555 root sys /usr/bin/lpstat systemv/lpstat + +# DSOs +%system hpux +f 0555 root sys /usr/lib/libcups.sl.2 cups/libcups.sl.2 +l 0555 root sys /usr/lib/libcups.sl libcups.sl.2 +f 0555 root sys /usr/lib/libcupsimage.sl.2 filter/libcupsimage.sl.2 +l 0555 root sys /usr/lib/libcupsimage.sl libcupsimage.sl.2 +%system irix-6.5 +f 0555 root sys /usr/lib32/libcups.so.2 cups/libcups.so.2 +l 0555 root sys /usr/lib32/libcups.so libcups.so.2 +f 0555 root sys /usr/lib32/libcupsimage.so.2 filter/libcupsimage.so.2 +l 0555 root sys /usr/lib32/libcupsimage.so libcupsimage.so.2 +%system !irix-6.5 !hpux +f 0555 root sys /usr/lib/libcups.so.2 cups/libcups.so.2 +l 0555 root sys /usr/lib/libcups.so libcups.so.2 +f 0555 root sys /usr/lib/libcupsimage.so.2 filter/libcupsimage.so.2 +l 0555 root sys /usr/lib/libcupsimage.so libcupsimage.so.2 +%system all + +# Directories +d 0711 root sys /etc/cups/certs +d 0755 root sys /etc/cups/interfaces +d 0755 root sys /etc/cups/ppd +d 0755 root sys /var/log/cups +d 0755 root sys /var/spool/cups + +# Data files +%system linux +f 0444 root sys /usr/share/locale/C/cups_C locale/C/cups_C +f 0444 root sys /usr/share/locale/de/cups_de locale/de/cups_de +f 0444 root sys /usr/share/locale/en/cups_en locale/en/cups_en +f 0444 root sys /usr/share/locale/es/cups_es locale/es/cups_es +f 0444 root sys /usr/share/locale/fr/cups_fr locale/fr/cups_fr +f 0444 root sys /usr/share/locale/it/cups_it locale/it/cups_it + +%system dunix +f 0444 root sys /usr/lib/nls/msg/C/cups_C locale/C/cups_C +f 0444 root sys /usr/lib/nls/msg/de/cups_de locale/de/cups_de +f 0444 root sys /usr/lib/nls/msg/en/cups_en locale/en/cups_en +f 0444 root sys /usr/lib/nls/msg/es/cups_es locale/es/cups_es +f 0444 root sys /usr/lib/nls/msg/fr/cups_fr locale/fr/cups_fr +f 0444 root sys /usr/lib/nls/msg/it/cups_it locale/it/cups_it + +%system !linux dunix +f 0444 root sys /usr/lib/locale/C/cups_C locale/C/cups_C +f 0444 root sys /usr/lib/locale/de/cups_de locale/de/cups_de +f 0444 root sys /usr/lib/locale/en/cups_en locale/en/cups_en +f 0444 root sys /usr/lib/locale/es/cups_es locale/es/cups_es +f 0444 root sys /usr/lib/locale/fr/cups_fr locale/fr/cups_fr +f 0444 root sys /usr/lib/locale/it/cups_it locale/it/cups_it + +%system all +f 0444 root sys /usr/share/cups/charsets/cp874 data/cp874 +f 0444 root sys /usr/share/cups/charsets/cp1250 data/cp1250 +f 0444 root sys /usr/share/cups/charsets/cp1251 data/cp1251 +f 0444 root sys /usr/share/cups/charsets/cp1252 data/cp1252 +f 0444 root sys /usr/share/cups/charsets/cp1253 data/cp1253 +f 0444 root sys /usr/share/cups/charsets/cp1254 data/cp1254 +f 0444 root sys /usr/share/cups/charsets/cp1255 data/cp1255 +f 0444 root sys /usr/share/cups/charsets/cp1256 data/cp1256 +f 0444 root sys /usr/share/cups/charsets/cp1257 data/cp1257 +f 0444 root sys /usr/share/cups/charsets/cp1258 data/cp1258 +f 0444 root sys /usr/share/cups/charsets/iso-8859-1 data/iso-8859-1 +f 0444 root sys /usr/share/cups/charsets/iso-8859-14 data/iso-8859-14 +f 0444 root sys /usr/share/cups/charsets/iso-8859-15 data/iso-8859-15 +f 0444 root sys /usr/share/cups/charsets/iso-8859-2 data/iso-8859-2 +f 0444 root sys /usr/share/cups/charsets/iso-8859-3 data/iso-8859-3 +f 0444 root sys /usr/share/cups/charsets/iso-8859-4 data/iso-8859-4 +f 0444 root sys /usr/share/cups/charsets/iso-8859-5 data/iso-8859-5 +f 0444 root sys /usr/share/cups/charsets/iso-8859-6 data/iso-8859-6 +f 0444 root sys /usr/share/cups/charsets/iso-8859-7 data/iso-8859-7 +f 0444 root sys /usr/share/cups/charsets/iso-8859-8 data/iso-8859-8 +f 0444 root sys /usr/share/cups/charsets/iso-8859-9 data/iso-8859-9 +f 0444 root sys /usr/share/cups/charsets/utf-8 data/utf-8 + +f 0444 root sys /usr/share/cups/data/HPGLprolog data/HPGLprolog +f 0444 root sys /usr/share/cups/data/psglyphs data/psglyphs +f 0444 root sys /usr/share/cups/data/testprint.ps data/testprint.ps +f 0444 root sys /usr/share/cups/fonts/AvantGarde-Book fonts/AvantGarde-Book +f 0444 root sys /usr/share/cups/fonts/AvantGarde-BookOblique fonts/AvantGarde-BookOblique +f 0444 root sys /usr/share/cups/fonts/AvantGarde-Demi fonts/AvantGarde-Demi +f 0444 root sys /usr/share/cups/fonts/AvantGarde-DemiOblique fonts/AvantGarde-DemiOblique +f 0444 root sys /usr/share/cups/fonts/Bookman-Demi fonts/Bookman-Demi +f 0444 root sys /usr/share/cups/fonts/Bookman-DemiItalic fonts/Bookman-DemiItalic +f 0444 root sys /usr/share/cups/fonts/Bookman-Light fonts/Bookman-Light +f 0444 root sys /usr/share/cups/fonts/Bookman-LightItalic fonts/Bookman-LightItalic +f 0444 root sys /usr/share/cups/fonts/Charter-Bold fonts/Charter-Bold +f 0444 root sys /usr/share/cups/fonts/Charter-BoldItalic fonts/Charter-BoldItalic +f 0444 root sys /usr/share/cups/fonts/Charter-Italic fonts/Charter-Italic +f 0444 root sys /usr/share/cups/fonts/Charter-Roman fonts/Charter-Roman +f 0444 root sys /usr/share/cups/fonts/Courier fonts/Courier +f 0444 root sys /usr/share/cups/fonts/Courier-Bold fonts/Courier-Bold +f 0444 root sys /usr/share/cups/fonts/Courier-BoldOblique fonts/Courier-BoldOblique +f 0444 root sys /usr/share/cups/fonts/Courier-Oblique fonts/Courier-Oblique +f 0444 root sys /usr/share/cups/fonts/Helvetica fonts/Helvetica +f 0444 root sys /usr/share/cups/fonts/Helvetica-Bold fonts/Helvetica-Bold +f 0444 root sys /usr/share/cups/fonts/Helvetica-BoldOblique fonts/Helvetica-BoldOblique +f 0444 root sys /usr/share/cups/fonts/Helvetica-Narrow fonts/Helvetica-Narrow +f 0444 root sys /usr/share/cups/fonts/Helvetica-Narrow-Bold fonts/Helvetica-Narrow-Bold +f 0444 root sys /usr/share/cups/fonts/Helvetica-Narrow-BoldOblique fonts/Helvetica-Narrow-BoldOblique +f 0444 root sys /usr/share/cups/fonts/Helvetica-Narrow-Oblique fonts/Helvetica-Narrow-Oblique +f 0444 root sys /usr/share/cups/fonts/Helvetica-Oblique fonts/Helvetica-Oblique +f 0444 root sys /usr/share/cups/fonts/NewCenturySchlbk-Bold fonts/NewCenturySchlbk-Bold +f 0444 root sys /usr/share/cups/fonts/NewCenturySchlbk-BoldItalic fonts/NewCenturySchlbk-BoldItalic +f 0444 root sys /usr/share/cups/fonts/NewCenturySchlbk-Italic fonts/NewCenturySchlbk-Italic +f 0444 root sys /usr/share/cups/fonts/NewCenturySchlbk-Roman fonts/NewCenturySchlbk-Roman +f 0444 root sys /usr/share/cups/fonts/Palatino-Bold fonts/Palatino-Bold +f 0444 root sys /usr/share/cups/fonts/Palatino-BoldItalic fonts/Palatino-BoldItalic +f 0444 root sys /usr/share/cups/fonts/Palatino-Italic fonts/Palatino-Italic +f 0444 root sys /usr/share/cups/fonts/Palatino-Roman fonts/Palatino-Roman +f 0444 root sys /usr/share/cups/fonts/Symbol fonts/Symbol +f 0444 root sys /usr/share/cups/fonts/Times-Bold fonts/Times-Bold +f 0444 root sys /usr/share/cups/fonts/Times-BoldItalic fonts/Times-BoldItalic +f 0444 root sys /usr/share/cups/fonts/Times-Italic fonts/Times-Italic +f 0444 root sys /usr/share/cups/fonts/Times-Roman fonts/Times-Roman +f 0444 root sys /usr/share/cups/fonts/Utopia-Bold fonts/Utopia-Bold +f 0444 root sys /usr/share/cups/fonts/Utopia-BoldItalic fonts/Utopia-BoldItalic +f 0444 root sys /usr/share/cups/fonts/Utopia-Italic fonts/Utopia-Italic +f 0444 root sys /usr/share/cups/fonts/Utopia-Regular fonts/Utopia-Regular +f 0444 root sys /usr/share/cups/fonts/ZapfChancery-MediumItalic fonts/ZapfChancery-MediumItalic +f 0444 root sys /usr/share/cups/fonts/ZapfDingbats fonts/ZapfDingbats +f 0444 root sys /usr/share/cups/pstoraster/Fontmap pstoraster/Fontmap +f 0444 root sys /usr/share/cups/pstoraster/gs_btokn.ps pstoraster/gs_btokn.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_ccfnt.ps pstoraster/gs_ccfnt.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_cff.ps pstoraster/gs_cff.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_cidfn.ps pstoraster/gs_cidfn.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_cmap.ps pstoraster/gs_cmap.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_cmdl.ps pstoraster/gs_cmdl.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_dbt_e.ps pstoraster/gs_dbt_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_diskf.ps pstoraster/gs_diskf.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_dpnxt.ps pstoraster/gs_dpnxt.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_dps1.ps pstoraster/gs_dps1.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_dps2.ps pstoraster/gs_dps2.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_dps.ps pstoraster/gs_dps.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_epsf.ps pstoraster/gs_epsf.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_fform.ps pstoraster/gs_fform.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_fonts.ps pstoraster/gs_fonts.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_init.ps pstoraster/gs_init.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_iso_e.ps pstoraster/gs_iso_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_kanji.ps pstoraster/gs_kanji.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_ksb_e.ps pstoraster/gs_ksb_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_l2img.ps pstoraster/gs_l2img.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_lev2.ps pstoraster/gs_lev2.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_ll3.ps pstoraster/gs_ll3.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_mex_e.ps pstoraster/gs_mex_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_mro_e.ps pstoraster/gs_mro_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_pdfwr.ps pstoraster/gs_pdfwr.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_pdf_e.ps pstoraster/gs_pdf_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_pfile.ps pstoraster/gs_pfile.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_res.ps pstoraster/gs_res.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_setpd.ps pstoraster/gs_setpd.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_statd.ps pstoraster/gs_statd.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_std_e.ps pstoraster/gs_std_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_sym_e.ps pstoraster/gs_sym_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_ttf.ps pstoraster/gs_ttf.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_typ32.ps pstoraster/gs_typ32.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_typ42.ps pstoraster/gs_typ42.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_type1.ps pstoraster/gs_type1.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_wan_e.ps pstoraster/gs_wan_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_wl1_e.ps pstoraster/gs_wl1_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_wl2_e.ps pstoraster/gs_wl2_e.ps +f 0444 root sys /usr/share/cups/pstoraster/gs_wl5_e.ps pstoraster/gs_wl5_e.ps +f 0444 root sys /usr/share/cups/pstoraster/pdf2dsc.ps pstoraster/pdf2dsc.ps +f 0444 root sys /usr/share/cups/pstoraster/pdf_base.ps pstoraster/pdf_base.ps +f 0444 root sys /usr/share/cups/pstoraster/pdf_draw.ps pstoraster/pdf_draw.ps +f 0444 root sys /usr/share/cups/pstoraster/pdf_font.ps pstoraster/pdf_font.ps +f 0444 root sys /usr/share/cups/pstoraster/pdf_main.ps pstoraster/pdf_main.ps +f 0444 root sys /usr/share/cups/pstoraster/pdf_ops.ps pstoraster/pdf_ops.ps +f 0444 root sys /usr/share/cups/pstoraster/pdf_sec.ps pstoraster/pdf_sec.ps +f 0444 root sys /usr/share/cups/model/deskjet.ppd ppd/deskjet.ppd +f 0444 root sys /usr/share/cups/model/laserjet.ppd ppd/laserjet.ppd +f 0444 root sys /usr/share/cups/model/stcolor.ppd ppd/stcolor.ppd +f 0444 root sys /usr/share/cups/model/stphoto.ppd ppd/stphoto.ppd + +f 0444 root sys /usr/share/cups/templates/add-class.tmpl templates/add-class.tmpl +f 0444 root sys /usr/share/cups/templates/add-printer.tmpl templates/add-printer.tmpl +f 0444 root sys /usr/share/cups/templates/admin-op.tmpl templates/admin-op.tmpl +f 0444 root sys /usr/share/cups/templates/admin.tmpl templates/admin.tmpl +f 0444 root sys /usr/share/cups/templates/choose-device.tmpl templates/choose-device.tmpl +f 0444 root sys /usr/share/cups/templates/choose-make.tmpl templates/choose-make.tmpl +f 0444 root sys /usr/share/cups/templates/choose-model.tmpl templates/choose-model.tmpl +f 0444 root sys /usr/share/cups/templates/choose-serial.tmpl templates/choose-serial.tmpl +f 0444 root sys /usr/share/cups/templates/choose-uri.tmpl templates/choose-uri.tmpl +f 0444 root sys /usr/share/cups/templates/classes.tmpl templates/classes.tmpl +f 0444 root sys /usr/share/cups/templates/error.tmpl templates/error.tmpl +f 0444 root sys /usr/share/cups/templates/header.tmpl templates/header.tmpl +f 0444 root sys /usr/share/cups/templates/job-cancel.tmpl templates/job-cancel.tmpl +f 0444 root sys /usr/share/cups/templates/job-hold.tmpl templates/job-hold.tmpl +f 0444 root sys /usr/share/cups/templates/job-release.tmpl templates/job-release.tmpl +f 0444 root sys /usr/share/cups/templates/jobs.tmpl templates/jobs.tmpl +f 0444 root sys /usr/share/cups/templates/modify-class.tmpl templates/modify-class.tmpl +f 0444 root sys /usr/share/cups/templates/modify-printer.tmpl templates/modify-printer.tmpl +f 0444 root sys /usr/share/cups/templates/option-boolean.tmpl templates/option-boolean.tmpl +f 0444 root sys /usr/share/cups/templates/option-header.tmpl templates/option-header.tmpl +f 0444 root sys /usr/share/cups/templates/option-pickmany.tmpl templates/option-pickmany.tmpl +f 0444 root sys /usr/share/cups/templates/option-pickone.tmpl templates/option-pickone.tmpl +f 0444 root sys /usr/share/cups/templates/option-trailer.tmpl templates/option-trailer.tmpl +f 0444 root sys /usr/share/cups/templates/printer-accept.tmpl templates/printer-accept.tmpl +f 0444 root sys /usr/share/cups/templates/printer-reject.tmpl templates/printer-reject.tmpl +f 0444 root sys /usr/share/cups/templates/printer-start.tmpl templates/printer-start.tmpl +f 0444 root sys /usr/share/cups/templates/printer-stop.tmpl templates/printer-stop.tmpl +f 0444 root sys /usr/share/cups/templates/printers.tmpl templates/printers.tmpl +f 0444 root sys /usr/share/cups/templates/test-page.tmpl templates/test-page.tmpl +f 0444 root sys /usr/share/cups/templates/trailer.tmpl templates/trailer.tmpl + +# Config files +c 0644 root sys /etc/cups/classes.conf conf/classes.conf +c 0644 root sys /etc/cups/cupsd.conf conf/cupsd.conf +f 0644 root sys /etc/cups/mime.convs conf/mime.convs +f 0644 root sys /etc/cups/mime.types conf/mime.types +c 0644 root sys /etc/cups/printers.conf conf/printers.conf + +# Dummy printcap file for Digital UNIX and Linux... +%system dunix linux +%format !rpm +f 0644 root sys /etc/printcap conf/printcap +%system all +%format all + +# Developer files +f 0444 root sys /usr/include/cups/cups.h cups/cups.h +f 0444 root sys /usr/include/cups/http.h cups/http.h +f 0444 root sys /usr/include/cups/image.h filter/image.h +f 0444 root sys /usr/include/cups/ipp.h cups/ipp.h +f 0444 root sys /usr/include/cups/language.h cups/language.h +f 0444 root sys /usr/include/cups/ppd.h cups/ppd.h +f 0444 root sys /usr/include/cups/raster.h filter/raster.h + +%system irix-6.5 +f 0444 root sys /usr/lib32/libcups.a cups/libcups.a +%system !irix-6.5 +f 0444 root sys /usr/lib/libcups.a cups/libcups.a +%system all + +# Documentation files +f 0444 root sys /usr/share/doc/cups/cups.css doc/cups.css +f 0444 root sys /usr/share/doc/cups/documentation.html doc/documentation.html +f 0444 root sys /usr/share/doc/cups/index.html doc/index.html + +f 0444 root sys /usr/share/doc/cups/images/accept-jobs.gif doc/images/accept-jobs.gif +f 0444 root sys /usr/share/doc/cups/images/add-class.gif doc/images/add-class.gif +f 0444 root sys /usr/share/doc/cups/images/add-printer.gif doc/images/add-printer.gif +f 0444 root sys /usr/share/doc/cups/images/cancel-job.gif doc/images/cancel-job.gif +f 0444 root sys /usr/share/doc/cups/images/cancel-jobs.gif doc/images/cancel-jobs.gif +f 0444 root sys /usr/share/doc/cups/images/cancel.gif doc/images/cancel.gif +f 0444 root sys /usr/share/doc/cups/images/classes.gif doc/images/classes.gif +f 0444 root sys /usr/share/doc/cups/images/continue.gif doc/images/continue.gif +f 0444 root sys /usr/share/doc/cups/images/cups-bar.gif doc/images/cups-bar.gif +f 0444 root sys /usr/share/doc/cups/images/cups-block-diagram.gif doc/images/cups-block-diagram.gif +f 0444 root sys /usr/share/doc/cups/images/cups-large.gif doc/images/cups-large.gif +f 0444 root sys /usr/share/doc/cups/images/cups-medium.gif doc/images/cups-medium.gif +f 0444 root sys /usr/share/doc/cups/images/cups-small.gif doc/images/cups-small.gif +f 0444 root sys /usr/share/doc/cups/images/delete-class.gif doc/images/delete-class.gif +f 0444 root sys /usr/share/doc/cups/images/delete-printer.gif doc/images/delete-printer.gif +f 0444 root sys /usr/share/doc/cups/images/hold-job.gif doc/images/hold-job.gif +f 0444 root sys /usr/share/doc/cups/images/left.gif doc/images/left.gif +f 0444 root sys /usr/share/doc/cups/images/logo.gif doc/images/logo.gif +f 0444 root sys /usr/share/doc/cups/images/manage-classes.gif doc/images/manage-classes.gif +f 0444 root sys /usr/share/doc/cups/images/manage-jobs.gif doc/images/manage-jobs.gif +f 0444 root sys /usr/share/doc/cups/images/manage-printers.gif doc/images/manage-printers.gif +f 0444 root sys /usr/share/doc/cups/images/modify-class.gif doc/images/modify-class.gif +f 0444 root sys /usr/share/doc/cups/images/modify-printer.gif doc/images/modify-printer.gif +f 0444 root sys /usr/share/doc/cups/images/navbar.gif doc/images/navbar.gif +f 0444 root sys /usr/share/doc/cups/images/print-test-page.gif doc/images/print-test-page.gif +f 0444 root sys /usr/share/doc/cups/images/printer-idle.gif doc/images/printer-idle.gif +f 0444 root sys /usr/share/doc/cups/images/printer-processing.gif doc/images/printer-processing.gif +f 0444 root sys /usr/share/doc/cups/images/printer-stopped.gif doc/images/printer-stopped.gif +f 0444 root sys /usr/share/doc/cups/images/reject-jobs.gif doc/images/reject-jobs.gif +f 0444 root sys /usr/share/doc/cups/images/release-job.gif doc/images/release-job.gif +f 0444 root sys /usr/share/doc/cups/images/restart-job.gif doc/images/restart-job.gif +f 0444 root sys /usr/share/doc/cups/images/right.gif doc/images/right.gif +f 0444 root sys /usr/share/doc/cups/images/show-active.gif doc/images/show-active.gif +f 0444 root sys /usr/share/doc/cups/images/show-completed.gif doc/images/show-completed.gif +f 0444 root sys /usr/share/doc/cups/images/start-class.gif doc/images/start-class.gif +f 0444 root sys /usr/share/doc/cups/images/start-printer.gif doc/images/start-printer.gif +f 0444 root sys /usr/share/doc/cups/images/stop-class.gif doc/images/stop-class.gif +f 0444 root sys /usr/share/doc/cups/images/stop-printer.gif doc/images/stop-printer.gif + +f 0444 root sys /usr/share/doc/cups/cmp.html doc/cmp.html +f 0444 root sys /usr/share/doc/cups/cmp.pdf doc/cmp.pdf +f 0444 root sys /usr/share/doc/cups/cupsdoc.css doc/cupsdoc.css +f 0444 root sys /usr/share/doc/cups/idd.html doc/idd.html +f 0444 root sys /usr/share/doc/cups/idd.pdf doc/idd.pdf +f 0444 root sys /usr/share/doc/cups/overview.html doc/overview.html +f 0444 root sys /usr/share/doc/cups/overview.pdf doc/overview.pdf +f 0444 root sys /usr/share/doc/cups/sam.html doc/sam.html +f 0444 root sys /usr/share/doc/cups/sam.pdf doc/sam.pdf +f 0444 root sys /usr/share/doc/cups/sdd.html doc/sdd.html +f 0444 root sys /usr/share/doc/cups/sdd.pdf doc/sdd.pdf +f 0444 root sys /usr/share/doc/cups/spm.html doc/spm.html +f 0444 root sys /usr/share/doc/cups/spm.pdf doc/spm.pdf +f 0444 root sys /usr/share/doc/cups/ssr.html doc/ssr.html +f 0444 root sys /usr/share/doc/cups/ssr.pdf doc/ssr.pdf +f 0444 root sys /usr/share/doc/cups/sum.html doc/sum.html +f 0444 root sys /usr/share/doc/cups/sum.pdf doc/sum.pdf + +# Man pages +%system irix +f 0444 root sys /usr/share/catman/a_man/cat1/accept.1 man/accept.8 +l 0444 root sys /usr/share/catman/a_man/cat1/reject.1 accept.1 +f 0444 root sys /usr/share/catman/u_man/cat1/backend.1 man/backend.1 +f 0444 root sys /usr/share/catman/u_man/cat5/classes.conf.5 man/classes.conf.5 +f 0444 root sys /usr/share/catman/u_man/cat5/cupsd.conf.5 man/cupsd.conf.5 +f 0444 root sys /usr/share/catman/a_man/cat1/cupsd.1 man/cupsd.8 +f 0444 root sys /usr/share/catman/a_man/cat1/enable.1 man/enable.8 +l 0444 root sys /usr/share/catman/a_man/cat1/disable.1 enable.1 +f 0444 root sys /usr/share/catman/u_man/cat1/filter.1 man/filter.1 +f 0444 root sys /usr/share/catman/a_man/cat1/lpadmin.1 man/lpadmin.8 +f 0444 root sys /usr/share/catman/a_man/cat1/lpc.1 man/lpc.8 +f 0444 root sys /usr/share/catman/u_man/cat1/lpq.1 man/lpq.1 +f 0444 root sys /usr/share/catman/u_man/cat1/lprm.1 man/lprm.1 +f 0444 root sys /usr/share/catman/u_man/cat1/lpr.1 man/lpr.1 +f 0444 root sys /usr/share/catman/u_man/cat1/lpstat.1 man/lpstat.1 +f 0444 root sys /usr/share/catman/u_man/cat1/lp.1 man/lp.1 +l 0444 root sys /usr/share/catman/u_man/cat1/cancel.1 lp.1 +f 0444 root sys /usr/share/catman/u_man/cat5/mime.convs.5 man/mime.convs.5 +f 0444 root sys /usr/share/catman/u_man/cat5/mime.types.5 man/mime.types.5 +f 0444 root sys /usr/share/catman/u_man/cat5/printers.conf.5 man/printers.conf.5 +%system !irix +f 0444 root sys /usr/man/man8/accept.8 man/accept.man +l 0444 root sys /usr/man/man8/reject.8 accept.man +f 0444 root sys /usr/man/man1/backend.1 man/backend.man +f 0444 root sys /usr/man/man1/classes.conf.5 man/classes.conf.man +f 0444 root sys /usr/man/man8/cupsd.8 man/cupsd.man +f 0444 root sys /usr/man/man5/cupsd.conf.5 man/cupsd.conf.man +f 0444 root sys /usr/man/man8/enable.8 man/enable.man +f 0444 root sys /usr/man/man8/esplicense.8 man/esplicense.man +l 0444 root sys /usr/man/man8/disable.8 enable.man +f 0444 root sys /usr/man/man1/filter.1 man/filter.man +f 0444 root sys /usr/man/man8/lpadmin.8 man/lpadmin.man +f 0444 root sys /usr/man/man8/lpc.8 man/lpc.man +f 0444 root sys /usr/man/man1/lpq.1 man/lpq.man +f 0444 root sys /usr/man/man1/lprm.1 man/lprm.man +f 0444 root sys /usr/man/man1/lpr.1 man/lpr.man +f 0444 root sys /usr/man/man1/lpstat.1 man/lpstat.man +f 0444 root sys /usr/man/man1/lp.1 man/lp.man +l 0444 root sys /usr/man/man1/cancel.1 lp.man +f 0444 root sys /usr/man/man5/mime.convs.5 man/mime.convs.man +f 0444 root sys /usr/man/man5/mime.types.5 man/mime.types.man +f 0444 root sys /usr/man/man5/printers.conf.5 man/printers.conf.man + +# Startup script +%system all +i 0555 root sys cups cups.sh + +# +# End of "$Id: cups.list 986 2000-03-13 18:56:08Z mike $". +# diff --git a/cups.sh b/cups.sh new file mode 100755 index 0000000000..a79cc0b43d --- /dev/null +++ b/cups.sh @@ -0,0 +1,117 @@ +#!/bin/sh +# +# "$Id$" +# +# Startup/shutdown script for the Common UNIX Printing System (CUPS). +# +# Linux chkconfig stuff: +# +# chkconfig: 02345 99 00 +# description: Startup/shutdown script for the Common UNIX \ +# Printing System (CUPS). +# +# Copyright 1997-2000 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* | Linux*) + 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 + +# Change to the root directory first, in case we are being run from a +# CD-ROM installation script... + +cd / + +# 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.spec b/cups.spec new file mode 100644 index 0000000000..05ba3cd313 --- /dev/null +++ b/cups.spec @@ -0,0 +1,116 @@ +# +# "$Id: cups.spec 904 2000-02-18 17:48:09Z mike $" +# +# RPM "spec" file for the Common UNIX Printing System (CUPS). +# +# Original version by Jason McMullan . +# +# Copyright 1999-2000 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 +# + +Summary: Common Unix Printing System +Name: cups +Version: 1.1a8 +Release: 0 +Copyright: GPL +Group: System Environment/Daemons +Source: ftp://ftp.easysw.com/pub/cups/beta/cups-1.1a8-source.tar.gz +Url: http://www.cups.org +Packager: Michael Sweet +Vendor: Easy Software Products +# use buildroot so as not to disturb the version already installed +BuildRoot: /tmp/rpmbuild +Conflicts: lpr + +%package devel +Summary: Common Unix Printing System - development environment +Group: Development/Libraries + +%description +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. + +%description devel +The Common UNIX Printing System provides a portable printing layer for +UNIX® operating systems. This is the development package for creating +additional printer drivers, and other CUPS services. + +%prep +%setup + +%build +./configure + +# If we got this far, all prerequisite libraries must be here. +make + +%install +# these lines just make sure the directory structure in the +# RPM_BUILD_ROOT exists +rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d + +make prefix=$RPM_BUILD_ROOT/usr LOGDIR=$RPM_BUILD_ROOT/var/log/cups \ + REQUESTS=$RPM_BUILD_ROOT/var/spool/cups \ + SERVERROOT=$RPM_BUILD_ROOT/etc/cups install + +install -m 755 -o root -g root cups.sh $RPM_BUILD_ROOT/etc/rc.d/init.d/cups + +%post +/sbin/chkconfig --add cups + +%preun +/sbin/chkconfig --del cups + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +/etc/rc.d/init.d/cups +%config /etc/cups/* +%dir /etc/cups/certs +%dir /etc/cups/interfaces +%dir /etc/cups/ppd +/usr/bin/* +%%attr(4555,root,root) /usr/bin/lppasswd +/usr/lib/* +/usr/man/* +/usr/sbin/* +%dir /usr/share/cups +/usr/share/cups/* +%dir /usr/share/doc/cups +/usr/share/doc/cups/* +%dir /var/cups +/usr/lib/cups/backend/* +/usr/lib/cups/cgi-bin/* +/usr/lib/cups/filter/* +%dir /var/spool/cups +%dir /var/log/cups + +%files devel +%dir /usr/include/cups +/usr/include/cups/* +/usr/lib/*.a + +# +# End of "$Id: cups.spec 904 2000-02-18 17:48:09Z mike $". +# diff --git a/cups/Makefile b/cups/Makefile new file mode 100644 index 0000000000..2b73302cf7 --- /dev/null +++ b/cups/Makefile @@ -0,0 +1,142 @@ +# +# "$Id$" +# +# Support library Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2000 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 = dest.o emit.o http.o ipp.o language.o mark.o md5.o options.o \ + page.o ppd.o snprintf.o string.o usersys.o util.o +OBJS = $(LIBOBJS) testhttp.o testppd.o + +# +# Header files to install... +# + +HEADERS = cups.h http.h ipp.h language.h ppd.h + +# +# Targets in this directory... +# + +TARGETS = $(LIBCUPS) testhttp testppd + +# +# Make all targets... +# + +all: $(TARGETS) + +# +# Remove object and target files... +# + +clean: + $(RM) $(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 \ + $(RM) `basename $(LIBCUPS) .2`; \ + $(LN) $(LIBCUPS) `basename $(LIBCUPS) .2`; \ + fi + +# +# libcups.so.2, libcups.sl.1 +# + +libcups.so.2 libcups.sl.2: $(LIBOBJS) ../Makedefs + echo Linking $@... + $(DSO) $@ $(LIBOBJS) + $(RM) `basename $@ .2` + $(LN) $@ `basename $@ .2` + +# +# 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 + +dest.o: cups.h http.h ipp.h language.h string.h +emit.o: ppd.h +http.o: http.h ipp.h md5.h string.h +ipp.o: http.h ipp.h string.h language.h +language.o: cups_C.h language.h string.h +mark.o: ppd.h +md5.o: md5.h +options.o: cups.h +page.o: ppd.h +ppd.o: language.h ppd.h +snprintf.o: string.h +string.o: string.h +usersys.o: cups.h +util.o: cups.h http.h ipp.h + +# +# 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 + +# +# 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 + +$(OBJS): ../Makedefs ../config.h + +# +# End of "$Id$". +# diff --git a/cups/cups.dsp b/cups/cups.dsp new file mode 100644 index 0000000000..cef2887657 --- /dev/null +++ b/cups/cups.dsp @@ -0,0 +1,180 @@ +# 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 ".." /I "../visualc" /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=.\snprintf.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..b717961367 --- /dev/null +++ b/cups/cups.h @@ -0,0 +1,145 @@ +/* + * "$Id$" + * + * API definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 + + +/* + * 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) */ +}; + +typedef struct /**** Printer Options ****/ +{ + char *name; /* Name of option */ + char *value; /* Value of option */ +} cups_option_t; + +typedef struct /**** Destination ****/ +{ + char *name, /* Printer or class name */ + *instance; /* Local instance name */ + int is_default; /* Is this printer the default? */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ +} cups_dest_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 ipp_status_t cupsLastError(void); +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 cupsAddDest(const char *name, const char *instance, + int num_dests, cups_dest_t **dests); +extern void cupsFreeDests(int num_dests, cups_dest_t *dests); +extern cups_dest_t *cupsGetDest(const char *name, const char *instance, + int num_dests, cups_dest_t *dests); +extern int cupsGetDests(cups_dest_t **dests); +extern void cupsSetDests(int num_dests, cups_dest_t *dests); + +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..d95beb1ed2 --- /dev/null +++ b/cups/cups_C.h @@ -0,0 +1,132 @@ +"us-ascii", +"OK", +"Cancel", +"Help", +"Quit", +"Close", +"Yes", +"No", +"On", +"Off", +"Save", +"Discard", +"Default", +"Options", +"More Info", +"Black", +"Color", +"Cyan", +"Magenta", +"Yellow", +"Copyright 1993-2000 by Easy Software Products, All Rights Reserved.", +"General", +"Printer", +"Image", +"HP-GL/2", +"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", +"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", +"Text", +"Pretty Print", +"Margins", +"Left", +"Right", +"Bottom", +"Top", +"Filename(s)", +"Print", +"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..c7918b9bf3 --- /dev/null +++ b/cups/debug.h @@ -0,0 +1,57 @@ +/* + * "$Id$" + * + * Debugging macros for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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/dest.c b/cups/dest.c new file mode 100644 index 0000000000..913cac7170 --- /dev/null +++ b/cups/dest.c @@ -0,0 +1,472 @@ +/* + * "$Id$" + * + * User-defined destination (and option) support for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2000 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: + * + * cupsAddDest() - Add a destination to the list of destinations. + * cupsFreeDests() - Free the memory used by the list of destinations. + * cupsGetDest() - Get the named destination from the list. + * cupsGetDests() - Get the list of destinations. + * cupsSetDests() - Set the list of destinations. + * cups_get_dests() - Get destinations from a file. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "string.h" +#include +#include + + +/* + * Local functions... + */ + +static int cups_get_dests(const char *filename, int num_dests, + cups_dest_t **dests); + + +/* + * 'cupsAddDest()' - Add a destination to the list of destinations. + */ + +int /* O - New number of destinations */ +cupsAddDest(const char *name, /* I - Name of destination */ + const char *instance, /* I - Instance of destination */ + int num_dests, /* I - Number of destinations */ + cups_dest_t **dests) /* IO - Destinations */ +{ + int i; /* Looping var */ + cups_dest_t *dest; /* Destination pointer */ + + + if (name == NULL || dests == NULL) + return (0); + + if ((dest = cupsGetDest(name, instance, num_dests, *dests)) != NULL) + return (num_dests); + + /* + * Add new destination... + */ + + if (num_dests == 0) + dest = malloc(sizeof(cups_dest_t)); + else + dest = realloc(*dests, sizeof(cups_dest_t) * (num_dests + 1)); + + if (dest == NULL) + return (num_dests); + + *dests = dest; + + for (i = num_dests; i > 0; i --, dest ++) + if (strcasecmp(name, dest->name) < 0) + break; + else if (instance == NULL && dest->instance != NULL) + break; + else if (instance != NULL && dest->instance != NULL && + strcasecmp(instance, dest->instance) < 0) + break; + + if (i > 0) + memmove(dest + 1, dest, i * sizeof(cups_dest_t)); + + dest->name = strdup(name); + dest->is_default = 0; + dest->num_options = 0; + dest->options = (cups_option_t *)0; + + if (instance == NULL) + dest->instance = NULL; + else + dest->instance = strdup(instance); + + return (num_dests + 1); +} + + +/* + * 'cupsFreeDests()' - Free the memory used by the list of destinations. + */ + +void +cupsFreeDests(int num_dests, /* I - Number of destinations */ + cups_dest_t *dests) /* I - Destinations */ +{ + int i; /* Looping var */ + cups_dest_t *dest; /* Current destination */ + + + if (num_dests == 0 || dests == NULL) + return; + + for (i = num_dests, dest = dests; i > 0; i --, dest ++) + { + free(dest->name); + + if (dest->instance) + free(dest->instance); + + cupsFreeOptions(dest->num_options, dest->options); + } + + free(dests); +} + + +/* + * 'cupsGetDest()' - Get the named destination from the list. + */ + +cups_dest_t * /* O - Destination pointer or NULL */ +cupsGetDest(const char *name, /* I - Name of destination */ + const char *instance, /* I - Instance of destination */ + int num_dests, /* I - Number of destinations */ + cups_dest_t *dests) /* I - Destinations */ +{ + int comp; /* Result of comparison */ + + + if (name == NULL || num_dests == 0 || dests == NULL) + return (NULL); + + while (num_dests > 0) + { + if ((comp = strcasecmp(name, dests->name)) < 0) + return (NULL); + else if (comp == 0) + { + if ((instance == NULL && dests->instance == NULL) || + (instance != NULL && dests->instance != NULL && + strcasecmp(instance, dests->instance) == 0)) + return (dests); + } + + num_dests --; + dests ++; + } + + return (NULL); +} + + +/* + * 'cupsGetDests()' - Get the list of destinations. + */ + +int /* O - Number of destinations */ +cupsGetDests(cups_dest_t **dests) /* O - Destinations */ +{ + int i; /* Looping var */ + int num_dests; /* Number of destinations */ + int count; /* Number of printers/classes */ + char **names; /* Printer/class names */ + cups_dest_t *dest; /* Destination pointer */ + const char *home; /* HOME environment variable */ + char filename[1024]; /* Local ~/.lpoptions file */ + + + /* + * Initialize destination array... + */ + + num_dests = 0; + *dests = (cups_dest_t *)0; + + /* + * Grab all available printers... + */ + + if ((count = cupsGetPrinters(&names)) > 0) + { + for (i = 0; i < count; i ++) + { + num_dests = cupsAddDest(names[i], NULL, num_dests, dests); + free(names[i]); + } + + free(names); + } + + /* + * Grab all available classes... + */ + + if ((count = cupsGetClasses(&names)) > 0) + { + for (i = 0; i < count; i ++) + { + num_dests = cupsAddDest(names[i], NULL, num_dests, dests); + free(names[i]); + } + + free(names); + } + + /* + * Grab the default destination... + */ + + if ((dest = cupsGetDest(cupsGetDefault(), NULL, num_dests, *dests)) != NULL) + dest->is_default = 1; + + /* + * Load the /etc/cups/lpoptions and ~/.lpoptions files... + */ + + num_dests = cups_get_dests(CUPS_SERVERROOT "/lpoptions", num_dests, dests); + + if ((home = getenv("HOME")) != NULL) + { + snprintf(filename, sizeof(filename), "%s/.lpoptions", home); + num_dests = cups_get_dests(filename, num_dests, dests); + } + + /* + * Return the number of destinations... + */ + + return (num_dests); +} + + +/* + * 'cupsSetDests()' - Set the list of destinations. + */ + +void +cupsSetDests(int num_dests, /* I - Number of destinations */ + cups_dest_t *dests) /* I - Destinations */ +{ + int i, j; /* Looping vars */ + cups_dest_t *dest; /* Current destination */ + cups_option_t *option; /* Current option */ + FILE *fp; /* File pointer */ + const char *home; /* HOME environment variable */ + char filename[1024]; /* lpoptions file */ + + + /* + * Figure out which file to write to... + */ + + if (getuid() == 0) + strcpy(filename, CUPS_SERVERROOT "/lpoptions"); + else if ((home = getenv("HOME")) != NULL) + snprintf(filename, sizeof(filename), "%s/.lpoptions", home); + else + return; + + /* + * Try to open the file... + */ + + if ((fp = fopen(filename, "w")) == NULL) + return; + + /* + * Write each printer; each line looks like: + * + * Dest name[/instance] options + * Default name[/instance] options + */ + + for (i = num_dests, dest = dests; i > 0; i --, dest ++) + if (dest->instance != NULL || dest->num_options != 0 || dest->is_default) + { + fprintf(fp, "%s %s", dest->is_default ? "Default" : "Dest", + dest->name); + if (dest->instance) + fprintf(fp, "/%s", dest->instance); + + for (j = dest->num_options, option = dest->options; j > 0; j --, option ++) + if (option->value[0]) + fprintf(fp, " %s=%s", option->name, option->value); + else + fprintf(fp, " %s", option->name); + + fputs("\n", fp); + } + + /* + * Close the file and return... + */ + + fclose(fp); +} + + +/* + * 'cups_get_dests()' - Get destinations from a file. + */ + +static int /* O - Number of destinations */ +cups_get_dests(const char *filename, /* I - File to read from */ + int num_dests, /* I - Number of destinations */ + cups_dest_t **dests) /* IO - Destinations */ +{ + int i; /* Looping var */ + cups_dest_t *dest; /* Current destination */ + FILE *fp; /* File pointer */ + char line[8192], /* Line from file */ + *lineptr, /* Pointer into line */ + *name, /* Name of destination/option */ + *instance; /* Instance of destination */ + + + /* + * Try to open the file... + */ + + if ((fp = fopen(filename, "r")) == NULL) + return (num_dests); + + /* + * Read each printer; each line looks like: + * + * Dest name[/instance] options + * Default name[/instance] options + */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * See what type of line it is... + */ + + if (strncasecmp(line, "dest", 4) == 0 && isspace(line[4])) + lineptr = line + 4; + else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7])) + lineptr = line + 7; + else + continue; + + /* + * Skip leading whitespace... + */ + + while (isspace(*lineptr)) + lineptr ++; + + if (!*lineptr) + continue; + + name = lineptr; + + /* + * Search for an instance... + */ + + while (!isspace(*lineptr) && *lineptr && *lineptr != '/') + lineptr ++; + + if (!*lineptr) + continue; + + if (*lineptr == '/') + { + /* + * Found an instance... + */ + + *lineptr++ = '\0'; + instance = lineptr; + + /* + * Search for an instance... + */ + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + } + else + instance = NULL; + + *lineptr++ = '\0'; + + /* + * Add the destination... + */ + + num_dests = cupsAddDest(name, instance, num_dests, dests); + + if ((dest = cupsGetDest(name, instance, num_dests, *dests)) == NULL) + { + /* + * Out of memory! + */ + + fclose(fp); + return (num_dests); + } + + /* + * Add options until we hit the end of the line... + */ + + if (dest->num_options) + { + /* + * Free old options... + */ + + cupsFreeOptions(dest->num_options, dest->options); + + dest->num_options = 0; + dest->options = (cups_option_t *)0; + } + + dest->num_options = cupsParseOptions(lineptr, dest->num_options, + &(dest->options)); + + /* + * Set this as default if needed... + */ + + if (strncasecmp(line, "default", 7) == 0) + { + for (i = 0; i < num_dests; i ++) + (*dests)[i].is_default = 0; + + dest->is_default = 1; + } + } + + /* + * Close the file and return... + */ + + fclose(fp); + + return (num_dests); +} + + +/* + * End of "$Id$". + */ diff --git a/cups/emit.c b/cups/emit.c new file mode 100644 index 0000000000..be56f5b97c --- /dev/null +++ b/cups/emit.c @@ -0,0 +1,301 @@ +/* + * "$Id$" + * + * PPD code emission routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 (strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageSize") == 0 && + strcasecmp(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/http.c b/cups/http.c new file mode 100644 index 0000000000..565ea99dba --- /dev/null +++ b/cups/http.c @@ -0,0 +1,1543 @@ +/* + * "$Id$" + * + * HTTP routines for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2000 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"... + */ + + strncpy(http->hostname, host, sizeof(http->hostname) - 1); + 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) + { +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + http->status = HTTP_ERROR; + 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) + { +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + http->status = HTTP_ERROR; + +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif + + return (-1); + } + + http->error = 0; + http->status = HTTP_CONTINUE; + + return (0); +} + + +/* + * 'httpSeparate()' - Separate a Universal Resource Identifier into its + * components. + */ + +void +httpSeparate(const char *uri, /* I - Universal Resource Identifier */ + char *method, /* O - Method [32] (http, https, etc.) */ + char *username, /* O - Username [32] */ + char *host, /* O - Hostname [32] */ + int *port, /* O - Port number to use */ + char *resource) /* O - Resource/filename [1024] */ +{ + 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... + */ + + if (strncmp(uri, "//", 2) == 0) + { + /* + * Workaround for HP IPP client bug... + */ + + strcpy(method, "ipp"); + } + else + { + /* + * Standard URI with method... + */ + + 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) + { + strncpy(resource, ptr, HTTP_MAX_URI - 1); + resource[HTTP_MAX_URI - 1] = '\0'; + *ptr = '\0'; + } + else + resource[0] = '\0'; + + if (isdigit(*uri)) + { + /* + * OK, we have "hostname:port[/resource]"... + */ + + *port = strtol(uri, (char **)&uri, 10); + + if (*uri == '/') + { + strncpy(resource, uri, HTTP_MAX_URI - 1); + resource[HTTP_MAX_URI - 1] = '\0'; + } + } + else + *port = 631; + + strcpy(method, "http"); + username[0] = '\0'; + return; + } + else + { + strncpy(method, host, 31); + method[31] = '\0'; + } + } + + /* + * If the method starts with less than 2 slashes then it is a local resource... + */ + + if (strncmp(uri, "//", 2) != 0) + { + strncpy(resource, uri, 1023); + resource[1023] = '\0'; + + username[0] = '\0'; + host[0] = '\0'; + *port = 0; + return; + } + + /* + * Grab the hostname... + */ + + while (*uri == '/') + uri ++; + + ptr = host; + while (!(*uri == ':' && isdigit(uri[1])) && *uri != '@' && *uri != '/' && *uri != '\0') + *ptr ++ = *uri ++; + + *ptr = '\0'; + + if (*uri == '@') + { + /* + * Got a username... + */ + + strncpy(username, host, 31); + username[31] = '\0'; + + ptr = host; + uri ++; + while (*uri != ':' && *uri != '/' && *uri != '\0') + *ptr ++ = *uri ++; + + *ptr = '\0'; + } + else + username[0] = '\0'; + + if (*uri != ':') + { + 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; + } + else + { + /* + * Parse port number... + */ + + *port = 0; + uri ++; + while (isdigit(*uri)) + { + *port = (*port * 10) + *uri - '0'; + uri ++; + } + } + + if (*uri == '\0') + { + /* + * Hostname but no port or path... + */ + + resource[0] = '/'; + resource[1] = '\0'; + return; + } + + /* + * The remaining portion is the resource string... + */ + + strncpy(resource, uri, HTTP_MAX_URI - 1); + resource[HTTP_MAX_URI - 1] = '\0'; +} + + +/* + * '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) + { + DEBUG_puts("httpRead: Getting chunk length..."); + + if (httpGets(len, sizeof(len), http) == NULL) + { + DEBUG_puts("httpRead: Could not get length!"); + 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) + 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) +#if defined(WIN32) || defined(__EMX__) + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 || __EMX__ */ + + if (http->data_remaining == 0) + { + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + 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 */ + + + if (http == NULL || buffer == NULL) + return (-1); + + http->activity = time(NULL); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + { + 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... + */ + + DEBUG_puts("httpWrite: changing states..."); + + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + + if (httpPrintf(http, "\r\n") < 0) + return (-1); + + 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) + 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... + */ + + DEBUG_puts("httpWrite: changing states..."); + + 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... + */ + +#if defined(WIN32) || defined(__EMX__) + WSASetLastError(0); +#else + errno = 0; +#endif /* WIN32 || __EMX__ */ + + 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 defined(WIN32) || defined(__EMX__) + if (WSAGetLastError() != http->error) + { + http->error = WSAGetLastError(); + continue; + } + + DEBUG_printf(("httpGets(): recv() error %d!\n", WSAGetLastError())); +#else + if (errno != http->error) + { + http->error = errno; + continue; + } + + DEBUG_printf(("httpGets(): recv() error %d!\n", errno)); +#endif /* WIN32 || __EMX__ */ + + 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 = vsnprintf(buf, sizeof(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%15s%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 + { + http->status = HTTP_ERROR; + return (HTTP_ERROR); + } + } + + /* + * See if there was an error... + */ + + if (http->error) + { + http->status = 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') + { + *outptr ++ = '='; + 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 */ +{ + DEBUG_printf(("httpGetLength(%08x)\n", http)); + + if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0) + { + DEBUG_puts("httpGetLength: chunked request!"); + + 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]); + + DEBUG_printf(("httpGetLength: content_length = %d\n", http->data_remaining)); + } + + 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'; + + /* + * See if we had an error the last time around; if so, reconnect... + */ + + if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST) + httpReconnect(http); + + /* + * 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) + { + http->status = HTTP_ERROR; + 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) + { + http->status = HTTP_ERROR; + return (-1); + } + } + + if (httpPrintf(http, "\r\n") < 1) + { + http->status = HTTP_ERROR; + 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..59206ca8b9 --- /dev/null +++ b/cups/http.h @@ -0,0 +1,315 @@ +/* + * "$Id$" + * + * Hyper-Text Transport Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2000 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__ */ + +# include "md5.h" + + +/* + * 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 authentication types... + */ + +typedef enum +{ + HTTP_AUTH_NONE, /* No authentication in use */ + HTTP_AUTH_BASIC, /* Basic authentication in use */ + HTTP_AUTH_MD5, /* Digest authentication in use */ + HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */ + HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */ + HTTP_AUTH_MD5_SESS_INT /* MD5-session authentication in use for body */ +} http_auth_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 */ + int auth_type; /* Authentication in use */ + md5_state_t md5_state; /* MD5 state */ + char nonce[HTTP_MAX_VALUE]; + /* Nonce value */ + int nonce_count; /* Nonce count */ +} 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..e48f191980 --- /dev/null +++ b/cups/ipp.c @@ -0,0 +1,1659 @@ +/* + * "$Id$" + * + * Internet Printing Protocol support functions for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2000 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. + * ippErrorString() - Return a textual message for the given error message. + * 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. + * _ipp_add_attr() - Add a new attribute to the request. + * ipp_read() - Semi-blocking read on a HTTP connection... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "string.h" +#include "language.h" + +#include "ipp.h" +#include "debug.h" + + +/* + * Local functions... + */ + +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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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 = _ipp_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; + + 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); +} + + +/* + * 'ippErrorString()' - Return a textual message for the given error message. + */ + +const char * /* O - Text string */ +ippErrorString(ipp_status_t error) /* I - Error status */ +{ + static cups_lang_t *language = 0; /* Language info */ + + + /* + * Load the localized message file as needed... + */ + + if (!language) + language = cupsLangDefault(); + + /* + * Return the appropriate message... + */ + + switch (error) + { + case IPP_OK : + case IPP_OK_SUBST : + case IPP_OK_CONFLICT : + return ("OK"); + + case IPP_BAD_REQUEST : + return (cupsLangString(language, HTTP_BAD_REQUEST)); + + case IPP_FORBIDDEN : + return (cupsLangString(language, HTTP_FORBIDDEN)); + + case IPP_NOT_AUTHENTICATED : + case IPP_NOT_AUTHORIZED : + return (cupsLangString(language, HTTP_UNAUTHORIZED)); + + case IPP_NOT_POSSIBLE : + return (cupsLangString(language, HTTP_METHOD_NOT_ALLOWED)); + + case IPP_TIMEOUT : + return (cupsLangString(language, HTTP_REQUEST_TIMEOUT)); + + case IPP_NOT_FOUND : + return (cupsLangString(language, HTTP_NOT_FOUND)); + + case IPP_GONE : + return (cupsLangString(language, HTTP_GONE)); + + case IPP_DOCUMENT_FORMAT : + return (cupsLangString(language, HTTP_UNSUPPORTED_MEDIATYPE)); + + case IPP_CONFLICT : + return (cupsLangString(language, HTTP_CONFLICT)); + + case IPP_INTERNAL_ERROR : + return (cupsLangString(language, HTTP_SERVER_ERROR)); + + case IPP_OPERATION_NOT_SUPPORTED : + case IPP_VERSION_NOT_SUPPORTED : + return (cupsLangString(language, HTTP_NOT_SUPPORTED)); + + case IPP_SERVICE_UNAVAILABLE : + case IPP_DEVICE_UNAVAILABLE : + case IPP_TEMPORARY_ERROR : + case IPP_PRINTER_BUSY : + return (cupsLangString(language, HTTP_SERVICE_UNAVAILABLE)); + + case IPP_NOT_ACCEPTING : + return (cupsLangString(language, CUPS_MSG_NOT_ACCEPTING_JOBS)); + } + + return ("ERROR"); +} + + +/* + * '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 && strcasecmp(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 += 4 * attr->num_values;/* Charset + text length */ + for (i = 0; i < attr->num_values; i ++) + bytes += strlen(attr->values[i].string.charset) + + strlen(attr->values[i].string.text); + break; + + default : + for (i = 0; i < attr->num_values; i ++) + bytes += attr->values[0].unknown.length; + break; + } + } + + /* + * Finally, add 1 byte for the "end of attributes" tag and return... + */ + + DEBUG_printf(("bytes = %d\n", bytes + 1)); + + return (bytes + 1); +} + + +/* + * 'ippNew()' - Allocate a new IPP request. + */ + +ipp_t * /* O - New IPP request */ +ippNew(void) +{ + ipp_t *temp; /* New IPP request */ + + + if ((temp = (ipp_t *)calloc(sizeof(ipp_t), 1)) != NULL) + { + /* + * Default to IPP 1.1... + */ + + temp->request.any.version[0] = 1; + temp->request.any.version[1] = 1; + } + + return (temp); +} + + +/* + * '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 */ + *bufptr; /* Pointer into 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_VALUE) + { + /* + * 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 = _ipp_add_attr(ipp, IPP_MAX_VALUES); + + attr->group_tag = ipp->curtag; + attr->value_tag = tag; + attr->name = strdup((char *)buffer); + attr->num_values = 0; + } + + if (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); + + bufptr = buffer; + + /* + * text-with-language and name-with-language are composite + * values: + * + * charset-length + * charset + * text-length + * text + */ + + n = (bufptr[0] << 8) | bufptr[1]; + + attr->values[attr->num_values].string.charset = calloc(n + 1, 1); + + memcpy(attr->values[attr->num_values].string.charset, + bufptr + 2, n); + + bufptr += 2 + n; + n = (bufptr[0] << 8) | bufptr[1]; + + attr->values[attr->num_values].string.text = calloc(n + 1, 1); + + memcpy(attr->values[attr->num_values].string.text, + bufptr + 2, n); + + break; + + default : /* Other unsupported values */ + attr->values[attr->num_values].unknown.length = n; + if (n > 0) + { + attr->values[attr->num_values].unknown.data = malloc(n); + if (ipp_read(http, attr->values[attr->num_values].unknown.data, n) < n) + return (IPP_ERROR); + } + else + attr->values[attr->num_values].unknown.data = NULL; + break; + } + + attr->num_values ++; + + /* + * 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++ = ipp->request.any.version[0]; + *bufptr++ = ipp->request.any.version[1]; + *bufptr++ = ipp->request.any.op_status >> 8; + *bufptr++ = ipp->request.any.op_status; + *bufptr++ = ipp->request.any.request_id >> 24; + *bufptr++ = ipp->request.any.request_id >> 16; + *bufptr++ = ipp->request.any.request_id >> 8; + *bufptr++ = ipp->request.any.request_id; + + if (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)); + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->values[i].string.text, n); + bufptr += n; + } + break; + + case IPP_TAG_DATE : + for (i = 0; i < attr->num_values; i ++) + { + if (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) + + strlen(attr->values[i].string.text) + + 2; + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + /* Length of entire value */ + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Length of charset */ + n = strlen(attr->values[i].string.charset); + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Charset */ + memcpy(bufptr, attr->values[i].string.charset, n); + bufptr += n; + + /* Length of text */ + n = strlen(attr->values[i].string.text); + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Text */ + memcpy(bufptr, attr->values[i].string.text, n); + bufptr += n; + } + break; + + default : + for (i = 0; i < attr->num_values; i ++) + { + if (i) + { + /* + * Arrays and sets are done by sending additional + * values with a zero-length name... + */ + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + n = attr->values[i].unknown.length; + + if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if (httpWrite(http, (char *)buffer, bufptr - buffer) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + /* Length of unknown value */ + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Value */ + if (n > 0) + { + memcpy(bufptr, attr->values[i].unknown.data, n); + bufptr += n; + } + } + break; + } + + /* + * Write the data out... + */ + + if (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)); +} + + +/* + * '_ipp_add_attr()' - Add a new attribute to the request. + */ + +ipp_attribute_t * /* O - New attribute */ +_ipp_add_attr(ipp_t *ipp, /* I - IPP request */ + int num_values) /* I - Number of values */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("_ipp_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..3ed874fe3b --- /dev/null +++ b/cups/ipp.h @@ -0,0 +1,358 @@ +/* + * "$Id$" + * + * Internet Printing Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2000 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_UNSUPPORTED_GROUP, + IPP_TAG_UNSUPPORTED_VALUE = 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_CANCELLED, + 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, + IPP_RELEASE_JOB, + IPP_RESTART_JOB, + IPP_PAUSE_PRINTER = 0x0010, + IPP_RESUME_PRINTER, + IPP_PURGE_JOBS, + IPP_SET_PRINTER_ATTRIBUTES, + IPP_SET_JOB_ATTRIBUTES, + IPP_GET_PRINTER_SUPPORTED_VALUES, + 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, + CUPS_GET_DEVICES, + CUPS_GET_PPDS +} 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 */ + + struct + { + int length; /* Length of attribute */ + void *data; /* Data in attribute */ + } unknown; /* Unknown attribute type */ +} 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 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 time_t ippDateToTime(const ipp_uchar_t *date); +extern void ippDelete(ipp_t *ipp); +extern const char *ippErrorString(ipp_status_t error); +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); + +extern ipp_attribute_t *_ipp_add_attr(ipp_t *, int); + + +/* + * 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..5e8cf71428 --- /dev/null +++ b/cups/language.c @@ -0,0 +1,390 @@ +/* + * "$Id$" + * + * I18N/language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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. Any trailing character set specification is + * dropped. + */ + + if (language == NULL || language[0] == '\0' || + strcmp(language, "POSIX") == 0) + strcpy(langname, "C"); + else + { + /* + * Copy the locale string over safely... + */ + + strncpy(langname, language, sizeof(langname) - 1); + langname[sizeof(langname) - 1] = '\0'; + + /* + * Strip charset from "locale.charset"... + */ + + if ((text = strchr(langname, '.')) != NULL) + *text = '\0'; + } + + 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; + + snprintf(filename, sizeof(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'; + snprintf(filename, sizeof(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..4f5b769547 --- /dev/null +++ b/cups/language.h @@ -0,0 +1,209 @@ +/* + * "$Id$" + * + * Multi-language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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_TEXT, + CUPS_MSG_PRETTYPRINT, + CUPS_MSG_MARGINS, + CUPS_MSG_LEFT, + CUPS_MSG_RIGHT, + CUPS_MSG_BOTTOM, + CUPS_MSG_TOP, + CUPS_MSG_FILENAME, + CUPS_MSG_PRINT, + 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..d6b79424e8 --- /dev/null +++ b/cups/mark.c @@ -0,0 +1,431 @@ +/* + * "$Id$" + * + * Option marking routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 || strcasecmp(c1->choice, "None") == 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 || strcasecmp(c2->choice, "None") == 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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(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 */ + + + 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 (strcasecmp(option, "PageSize") == 0 && strncasecmp(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 (strcasecmp(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 (strcasecmp(c->choice, choice) != 0) + c->marked = 0; + + if (strcasecmp(option, "PageSize") == 0 || strcasecmp(option, "PageRegion") == 0) + { + /* + * Mark current page size... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + ppd->sizes[i].marked = strcasecmp(ppd->sizes[i].name, choice) == 0; + + /* + * Unmark the current PageSize or PageRegion setting, as appropriate... + */ + + if (strcasecmp(option, "PageSize") == 0) + { + if ((o = ppdFindOption(ppd, "PageRegion")) != NULL) + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + else + { + if ((o = ppdFindOption(ppd, "PageSize")) != NULL) + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + } + else if (strcasecmp(option, "InputSlot") == 0) + { + /* + * Unmark ManualFeed option... + */ + + if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL) + for (i = 0; i < o->num_choices; i ++) + o->choices[i].marked = 0; + } + else if (strcasecmp(option, "ManualFeed") == 0) + { + /* + * Unmark InputSlot option... + */ + + if ((o = ppdFindOption(ppd, "InputSlot")) != NULL) + 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 (strcasecmp(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/md5.c b/cups/md5.c new file mode 100644 index 0000000000..5db868858e --- /dev/null +++ b/cups/md5.c @@ -0,0 +1,392 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/*$Id$ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include "string.h" + +#ifdef TEST +/* + * Compile with -DTEST to create a self-contained executable test program. + * The test program should print out the same values as given in section + * A.5 of RFC 1321, reproduced below. + */ +main() +{ + static const char *const test[7] = { + "", /*d41d8cd98f00b204e9800998ecf8427e*/ + "a", /*0cc175b9c0f1b6a831c399e269772661*/ + "abc", /*900150983cd24fb0d6963f7d28e17f72*/ + "message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/ + "abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + /*d174ab98d277d9f5a5611c2c9f419d9f*/ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/ + }; + int i; + + for (i = 0; i < 7; ++i) { + md5_state_t state; + md5_byte_t digest[16]; + int di; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); + md5_finish(&state, digest); + printf("MD5 (\"%s\") = ", test[i]); + for (di = 0; di < 16; ++di) + printf("%02x", digest[di]); + printf("\n"); + } + return 0; +} +#endif /* TEST */ + + +/* + * For reference, here is the program that computed the T values. + */ +#if 0 +#include +main() +{ + int i; + for (i = 1; i <= 64; ++i) { + unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); + printf("#define T%d 0x%08lx\n", i, v); + } + return 0; +} +#endif +/* + * End of T computation program. + */ +#define T1 0xd76aa478 +#define T2 0xe8c7b756 +#define T3 0x242070db +#define T4 0xc1bdceee +#define T5 0xf57c0faf +#define T6 0x4787c62a +#define T7 0xa8304613 +#define T8 0xfd469501 +#define T9 0x698098d8 +#define T10 0x8b44f7af +#define T11 0xffff5bb1 +#define T12 0x895cd7be +#define T13 0x6b901122 +#define T14 0xfd987193 +#define T15 0xa679438e +#define T16 0x49b40821 +#define T17 0xf61e2562 +#define T18 0xc040b340 +#define T19 0x265e5a51 +#define T20 0xe9b6c7aa +#define T21 0xd62f105d +#define T22 0x02441453 +#define T23 0xd8a1e681 +#define T24 0xe7d3fbc8 +#define T25 0x21e1cde6 +#define T26 0xc33707d6 +#define T27 0xf4d50d87 +#define T28 0x455a14ed +#define T29 0xa9e3e905 +#define T30 0xfcefa3f8 +#define T31 0x676f02d9 +#define T32 0x8d2a4c8a +#define T33 0xfffa3942 +#define T34 0x8771f681 +#define T35 0x6d9d6122 +#define T36 0xfde5380c +#define T37 0xa4beea44 +#define T38 0x4bdecfa9 +#define T39 0xf6bb4b60 +#define T40 0xbebfbc70 +#define T41 0x289b7ec6 +#define T42 0xeaa127fa +#define T43 0xd4ef3085 +#define T44 0x04881d05 +#define T45 0xd9d4d039 +#define T46 0xe6db99e5 +#define T47 0x1fa27cf8 +#define T48 0xc4ac5665 +#define T49 0xf4292244 +#define T50 0x432aff97 +#define T51 0xab9423a7 +#define T52 0xfc93a039 +#define T53 0x655b59c3 +#define T54 0x8f0ccc92 +#define T55 0xffeff47d +#define T56 0x85845dd1 +#define T57 0x6fa87e4f +#define T58 0xfe2ce6e0 +#define T59 0xa3014314 +#define T60 0x4e0811a1 +#define T61 0xf7537e82 +#define T62 0xbd3af235 +#define T63 0x2ad7d2bb +#define T64 0xeb86d391 + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + +#ifndef ARCH_IS_BIG_ENDIAN +# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ +#endif +#if ARCH_IS_BIG_ENDIAN + + /* + * On big-endian machines, we must arrange the bytes in the right + * order. (This also works on machines of unknown byte order.) + */ + md5_word_t X[16]; + const md5_byte_t *xp = data; + int i; + + for (i = 0; i < 16; ++i, xp += 4) + X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + +#else /* !ARCH_IS_BIG_ENDIAN */ + + /* + * On little-endian machines, we can process properly aligned data + * without copying it. + */ + md5_word_t xbuf[16]; + const md5_word_t *X; + + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } +#endif + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = 0xefcdab89; + pms->abcd[2] = 0x98badcfe; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 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, 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 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/cups/md5.h b/cups/md5.h new file mode 100644 index 0000000000..a2d7b34156 --- /dev/null +++ b/cups/md5.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/*$Id$ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This code has some adaptations for the Ghostscript environment, but it + * will compile and run correctly in any environment with 8-bit chars and + * 32-bit ints. Specifically, it assumes that if the following are + * defined, they have the same meaning as in Ghostscript: P1, P2, P3, + * ARCH_IS_BIG_ENDIAN. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +#ifdef P1 +void md5_init(P1(md5_state_t *pms)); +#else +void md5_init(md5_state_t *pms); +#endif + +/* Append a string to the message. */ +#ifdef P3 +void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes)); +#else +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); +#endif + +/* Finish the message and return the digest. */ +#ifdef P2 +void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16])); +#else +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); +#endif + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/cups/options.c b/cups/options.c new file mode 100644 index 0000000000..d8170ca5be --- /dev/null +++ b/cups/options.c @@ -0,0 +1,379 @@ +/* + * "$Id$" + * + * Option routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(options->name, "sides") == 0) + { + if (strcasecmp(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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(options->name, "resolution") == 0 || + strcasecmp(options->name, "printer-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..b9a206948b --- /dev/null +++ b/cups/page.c @@ -0,0 +1,189 @@ +/* + * "$Id$" + * + * Page size functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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%254s", &w, &l, units) < 2) + return (NULL); + + if (strcasecmp(units, "in") == 0) + { + ppd->sizes[i].width = w * 72.0f; + ppd->sizes[i].length = l * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l * 72.0f - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "cm") == 0) + { + ppd->sizes[i].width = w / 2.54f * 72.0f; + ppd->sizes[i].length = l / 2.54f * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w / 2.54f * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l / 2.54f * 72.0f - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "mm") == 0) + { + ppd->sizes[i].width = w / 25.4f * 72.0f; + ppd->sizes[i].length = l / 25.4f * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w / 25.4f * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l / 25.4f * 72.0f - 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..2e84cdbca4 --- /dev/null +++ b/cups/ppd.c @@ -0,0 +1,1816 @@ +/* + * "$Id$" + * + * PPD file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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, "Throughput") == 0) + ppd->throughput = atoi(string); + else if (strcmp(keyword, "VariablePaperSize") == 0 && + strcmp(string, "True") == 0 && + !ppd->variable_sizes) + { + 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] = (float)atof(string); + else if (strcmp(keyword, "MaxMediaHeight") == 0) + ppd->custom_max[1] = (float)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) + { + if (!ppd->variable_sizes) + { + 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; + } + + 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%40s%40s", &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..c093e454c8 --- /dev/null +++ b/cups/ppd.h @@ -0,0 +1,240 @@ +/* + * "$Id$" + * + * PostScript Printer Description definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2000 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 */ + throughput; /* Pages per minute */ + 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/snprintf.c b/cups/snprintf.c new file mode 100644 index 0000000000..2cb180ed95 --- /dev/null +++ b/cups/snprintf.c @@ -0,0 +1,287 @@ +/* + * "$Id$" + * + * snprintf functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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: + * + * vsnprintf() - Format a string into a fixed size buffer. + * snprintf() - Format a string into a fixed size buffer. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "string.h" + + +#ifndef HAVE_VSNPRINTF +/* + * 'vsnprintf()' - Format a string into a fixed size buffer. + */ + +int /* O - Number of bytes formatted */ +vsnprintf(char *buffer, /* O - Output buffer */ + size_t bufsize, /* O - Size of output buffer */ + const char *format, /* I - printf-style format string */ + va_list ap) /* I - Pointer to additional arguments */ +{ + char *bufptr, /* Pointer to position in buffer */ + *bufend, /* Pointer to end of buffer */ + sign, /* Sign of format width */ + size, /* Size character (h, l, L) */ + type; /* Format type character */ + const char *bufformat; /* Start of format */ + int width, /* Width of field */ + prec; /* Number of characters of precision */ + char tformat[100], /* Temporary format string for sprintf() */ + temp[1024]; /* Buffer for formatted numbers */ + int *chars; /* Pointer to integer for %p */ + char *s; /* Pointer to string */ + int slen; /* Length of string */ + + + /* + * Loop through the format string, formatting as needed... + */ + + bufptr = buffer; + bufend = buffer + bufsize - 1; + + while (*format && bufptr < bufend) + { + if (*format == '%') + { + bufformat = format; + format ++; + + if (*format == '%') + { + *bufptr++ = *format++; + continue; + } + else if (strchr(" -+#\'", *format)) + sign = *format++; + else + sign = 0; + + width = 0; + while (isdigit(*format)) + width = width * 10 + *format++ - '0'; + + if (*format == '.') + { + format ++; + prec = 0; + + while (isdigit(*format)) + prec = prec * 10 + *format++ - '0'; + } + else + prec = -1; + + if (*format == 'l' && format[1] == 'l') + { + size = 'L'; + format += 2; + } + else if (*format == 'h' || *format == 'l' || *format == 'L') + size = *format++; + + if (!*format) + break; + + type = *format++; + + switch (type) + { + case 'E' : /* Floating point formats */ + case 'G' : + case 'e' : + case 'f' : + case 'g' : + if ((format - bufformat + 1) > sizeof(tformat) || + (width + 2) > sizeof(temp)) + break; + + strncpy(tformat, bufformat, format - bufformat); + tformat[format - bufformat] = '\0'; + + sprintf(temp, tformat, va_arg(ap, double)); + + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, bufend - bufptr); + bufptr = bufend; + break; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + break; + + case 'B' : /* Integer formats */ + case 'X' : + case 'b' : + case 'd' : + case 'i' : + case 'o' : + case 'u' : + case 'x' : + if ((format - bufformat + 1) > sizeof(tformat) || + (width + 2) > sizeof(temp)) + break; + + strncpy(tformat, bufformat, format - bufformat); + tformat[format - bufformat] = '\0'; + + sprintf(temp, tformat, va_arg(ap, int)); + + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, bufend - bufptr); + bufptr = bufend; + break; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + break; + + case 'p' : /* Pointer value */ + if ((chars = va_arg(ap, int *)) != NULL) + *chars = bufptr - buffer; + break; + + case 'c' : /* Character or character array */ + if (width <= 1) + *bufptr++ = va_arg(ap, int); + else + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + memcpy(bufptr, va_arg(ap, char *), width); + bufptr += width; + } + break; + + case 's' : /* String */ + if ((s = va_arg(ap, char *)) == NULL) + s = "(null)"; + + slen = strlen(s); + if (slen > width && prec != width) + width = slen; + + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + if (slen > width) + slen = width; + + if (sign == '-') + { + strncpy(bufptr, s, slen); + memset(bufptr + slen, ' ', width - slen); + } + else + { + memset(bufptr, ' ', width - slen); + strncpy(bufptr + width - slen, s, slen); + } + + bufptr += width; + break; + + case 'n' : /* Output number of chars so far */ + if ((format - bufformat + 1) > sizeof(tformat) || + (width + 2) > sizeof(temp)) + break; + + strncpy(tformat, bufformat, format - bufformat); + tformat[format - bufformat] = '\0'; + + sprintf(temp, tformat, va_arg(ap, int)); + + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, bufend - bufptr); + bufptr = bufend; + break; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + break; + } + } + else + *bufptr++ = *format++; + } + + /* + * Nul-terminate the string and return the number of characters in it. + */ + + *bufptr = '\0'; + return (bufptr - buffer); +} +#endif /* !HAVE_VSNPRINT */ + + +#ifndef HAVE_SNPRINTF +/* + * 'snprintf()' - Format a string into a fixed size buffer. + */ + +int /* O - Number of bytes formatted */ +snprintf(char *buffer, /* O - Output buffer */ + size_t bufsize, /* O - Size of output buffer */ + const char *format, /* I - printf-style format string */ + ...) /* I - Additional arguments as needed */ +{ + int bytes; /* Number of bytes formatted */ + va_list ap; /* Pointer to additional arguments */ + + + va_start(ap, format); + bytes = vsnprintf(buffer, bufsize, format, ap); + va_end(ap); + + return (bytes); +} +#endif /* !HAVE_SNPRINTF */ + + +/* + * End of "$Id$". + */ + diff --git a/cups/string.c b/cups/string.c new file mode 100644 index 0000000000..b295162c73 --- /dev/null +++ b/cups/string.c @@ -0,0 +1,125 @@ +/* + * "$Id$" + * + * String functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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..5c3464ae76 --- /dev/null +++ b/cups/string.h @@ -0,0 +1,94 @@ +/* + * "$Id$" + * + * String definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 +# include +# include + + +/* + * Stuff for WIN32 and OS/2... + */ + +# if defined(WIN32) || defined(__EMX__) +# define strcasecmp stricmp +# define strncasecmp strnicmp +# endif /* WIN32 || __EMX__ */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * 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 */ + +# ifndef HAVE_SNPRINTF +extern int snprintf(char *, size_t, const char *, ...); +# endif /* !HAVE_SNPRINTF */ + +# ifndef HAVE_VSNPRINTF +extern int vsnprintf(char *, size_t, const char *, va_list); +# endif /* !HAVE_VSNPRINTF */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_STRING_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/testhttp.c b/cups/testhttp.c new file mode 100644 index 0000000000..9d1dde6593 --- /dev/null +++ b/cups/testhttp.c @@ -0,0 +1,109 @@ +/* + * "$Id$" + * + * HTTP test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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.dsp b/cups/testmime.dsp new file mode 100644 index 0000000000..33fbd301af --- /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 ".." /I "../visualc" /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..bf9e5b21c2 --- /dev/null +++ b/cups/testppd.c @@ -0,0 +1,183 @@ +/* + * "$Id$" + * + * PPD test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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; /* 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..27d4f035ce --- /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 ".." /I "../visualc" /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/usersys.c b/cups/usersys.c new file mode 100644 index 0000000000..154695adad --- /dev/null +++ b/cups/usersys.c @@ -0,0 +1,181 @@ +/* + * "$Id$" + * + * User, system, and password routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2000 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: + * + * cupsUser() - Return the current users name. + * cupsGetPassword() - Get a password from the user... + * cupsServer() - Return the hostname of the default server... + */ + +/* + * 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; /* client.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 client.conf file... + */ + + if ((fp = fopen(CUPS_SERVERROOT "/client.conf", "r")) == NULL) + return ("localhost"); + + /* + * Read the client.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) + { + fclose(fp); + 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..32054b4e64 --- /dev/null +++ b/cups/util.c @@ -0,0 +1,1270 @@ +/* + * "$Id$" + * + * Printing utilities for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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... + * cups_local_auth() - Get the local authorization certificate if + * available/applicable... + */ + +/* + * 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; /* Current server connection */ +static ipp_status_t last_error = IPP_OK; /* Last IPP error */ +static char authstring[255] = ""; /* Authorization string */ + + +/* + * Local functions... + */ + +static char *cups_connect(const char *name, char *printer, char *hostname); +static int cups_local_auth(http_t *http); + + +/* + * '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)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (0); + } + + /* + * Build an IPP_CANCEL_JOB request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * job-id + * [requesting-user-name] + */ + + 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"); + + snprintf(uri, sizeof(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); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, cupsUser()); + + /* + * Do the request... + */ + + if ((response = cupsDoRequest(cups_server, request, "/jobs/")) == NULL) + { + last_error = IPP_BAD_REQUEST; + return (0); + } + else + { + last_error = response->request.status.status_code; + 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 */ + + + 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); + last_error = IPP_NOT_FOUND; + return (NULL); + } + + if ((file = fopen(filename, "rb")) == NULL) + { + /* + * Can't open file! + */ + + ippDelete(request); + last_error = IPP_NOT_FOUND; + 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)) + 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); + + /* + * See if we can do local authentication... + */ + + if (cups_local_auth(http)) + continue; + + /* + * Nope - get a password from the user... + */ + + printf("Authentication required for %s on %s...\n", cupsUser(), + http->hostname); + + if ((password = cupsGetPassword("UNIX Password: ")) != NULL) + { + /* + * Got a password; send it to the server... + */ + + if (!password[0]) + break; + snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), password); + httpEncode64(encode, plain); + snprintf(authstring, sizeof(authstring), "Basic %s", encode); + + continue; + } + else + break; + } + else if (status == HTTP_ERROR) + { +#if defined(WIN32) || defined(__EMX__) + if (http->error != WSAENETDOWN && http->error != WSAENETUNREACH) +#else + if (http->error != ENETDOWN && http->error != ENETUNREACH) +#endif /* WIN32 || __EMX__ */ + continue; + else + break; + } + else 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; + + last_error = IPP_SERVICE_UNAVAILABLE; + + /* + * 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); + + if (response) + last_error = response->request.status.status_code; + else if (status == HTTP_NOT_FOUND) + last_error = IPP_NOT_FOUND; + else if (status == HTTP_UNAUTHORIZED) + last_error = IPP_NOT_AUTHORIZED; + else if (status != HTTP_OK) + last_error = IPP_SERVICE_UNAVAILABLE; + + 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 */ + char **temp; /* Temporary pointer */ + + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + 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, "/")) != NULL) + { + last_error = response->request.status.status_code; + + for (attr = response->attrs; attr != NULL; attr = attr->next) + if (attr->name != NULL && + strcasecmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + { + if (n == 0) + temp = malloc(sizeof(char *)); + else + temp = realloc(*classes, sizeof(char *) * (n + 1)); + + if (temp == NULL) + { + /* + * Ran out of memory! + */ + + while (n > 0) + { + n --; + free((*classes)[n]); + } + + free(*classes); + ippDelete(response); + return (0); + } + + *classes = temp; + temp[n] = strdup(attr->values[0].string.text); + n ++; + } + + ippDelete(response); + } + else + last_error = IPP_BAD_REQUEST; + + return (n); +} + + +/* + * 'cupsGetDefault()' - Get the default printer or class. + */ + +const char * /* O - Default printer or NULL */ +cupsGetDefault(void) +{ + FILE *fp; /* cupsd.conf file */ + char *printer; /* Pointer to server name */ + char line[1024]; /* Line from file */ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + const char *var; /* Environment variable */ + static char def_printer[256];/* Default printer */ + + + /* + * First see if the LPDEST or PRINTER environment variables are + * set... However, if PRINTER is set to "lp", ignore it to work + * around a "feature" in most Linux distributions - the default + * user login scripts set PRINTER to "lp"... + */ + + if ((var = getenv("LPDEST")) != NULL) + return (var); + else if ((var = getenv("PRINTER")) != NULL && strcmp(var, "lp") != 0) + return (var); + + /* + * Next check to see if we have a client.conf file... + */ + + if ((fp = fopen(CUPS_SERVERROOT "/client.conf", "r")) != NULL) + { + /* + * Read the client.conf file and look for a DefaultPrinter line... + */ + + while (fgets(line, sizeof(line), fp) != NULL) + if (strncmp(line, "DefaultPrinter ", 15) == 0) + { + /* + * Got it! Drop any trailing newline and find the name... + */ + + printer = line + strlen(line) - 1; + if (*printer == '\n') + *printer = '\0'; + + for (printer = line + 15; isspace(*printer); printer ++); + + if (*printer) + { + strncpy(def_printer, printer, sizeof(def_printer) - 1); + def_printer[sizeof(def_printer) - 1] = '\0'; + + fclose(fp); + + return (def_printer); + } + } + + fclose(fp); + } + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + 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, "/")) != NULL) + { + last_error = response->request.status.status_code; + + if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) + { + strncpy(def_printer, attr->values[0].string.text, sizeof(def_printer) - 1); + def_printer[sizeof(def_printer) - 1] = '\0'; + ippDelete(response); + return (def_printer); + } + + ippDelete(response); + } + else + last_error = IPP_BAD_REQUEST; + + 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 */ + char *tempdir; /* Temporary file directory */ + const char *password; /* Password string */ + char plain[255], /* Plaintext username:password */ + encode[255]; /* Encoded username:password */ + http_status_t status; /* HTTP status from server */ + static char filename[HTTP_MAX_URI]; /* Local filename */ + + + /* + * See if we can connect to the server... + */ + + if (!cups_connect(name, printer, hostname)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (NULL); + } + + /* + * Then check for the cache file... + */ + +#if defined(WIN32) || defined(__EMX__) + tempdir = "C:/WINDOWS/TEMP"; + + snprintf(filename, sizeof(filename), "%s/%s.ppd", tempdir, printer); +#else + if ((tempdir = getenv("TMPDIR")) == NULL) + tempdir = "/tmp"; + + snprintf(filename, sizeof(filename), "%s/%d.%s.ppd", tempdir, getuid(), printer); +#endif /* WIN32 || __EMX__ */ + + /* + * And send a request to the HTTP server... + */ + + snprintf(resource, sizeof(resource), "/printers/%s.ppd", printer); + + do + { + httpClearFields(cups_server); + httpSetField(cups_server, HTTP_FIELD_HOST, hostname); + httpSetField(cups_server, HTTP_FIELD_AUTHORIZATION, authstring); + + if (httpGet(cups_server, resource)) + { + status = HTTP_UNAUTHORIZED; + continue; + } + + while ((status = httpUpdate(cups_server)) == HTTP_CONTINUE); + + if (status == HTTP_UNAUTHORIZED) + { + DEBUG_puts("cupsGetPPD: unauthorized..."); + + /* + * Flush any error message... + */ + + httpFlush(cups_server); + + /* + * See if we can do local authentication... + */ + + if (cups_local_auth(cups_server)) + continue; + + /* + * Nope, get a password from the user... + */ + + printf("Authentication required for %s on %s...\n", cupsUser(), + cups_server->hostname); + + if ((password = cupsGetPassword("UNIX Password: ")) != NULL) + { + /* + * Got a password; send it to the server... + */ + + if (!password[0]) + break; + snprintf(plain, sizeof(plain), "%s:%s", cupsUser(), password); + httpEncode64(encode, plain); + snprintf(authstring, sizeof(authstring), "Basic %s", encode); + + continue; + } + else + break; + } + } + while (status == HTTP_UNAUTHORIZED); + + /* + * 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 */ + char **temp; /* Temporary pointer */ + + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + last_error = IPP_SERVICE_UNAVAILABLE; + 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, "/")) != NULL) + { + last_error = response->request.status.status_code; + + for (attr = response->attrs; attr != NULL; attr = attr->next) + if (attr->name != NULL && + strcasecmp(attr->name, "printer-name") == 0 && + attr->value_tag == IPP_TAG_NAME) + { + if (n == 0) + temp = malloc(sizeof(char *)); + else + temp = realloc(*printers, sizeof(char *) * (n + 1)); + + if (temp == NULL) + { + /* + * Ran out of memory! + */ + + while (n > 0) + { + n --; + free((*printers)[n]); + } + + free(*printers); + ippDelete(response); + return (0); + } + + *printers = temp; + temp[n] = strdup(attr->values[0].string.text); + n ++; + } + + ippDelete(response); + } + else + last_error = IPP_BAD_REQUEST; + + return (n); +} + + +/* + * 'cupsLastError()' - Return the last IPP error that occurred. + */ + +ipp_status_t /* O - IPP error code */ +cupsLastError(void) +{ + return (last_error); +} + + +/* + * '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))); + last_error = IPP_SERVICE_UNAVAILABLE; + 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; + + snprintf(uri, sizeof(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 (strcasecmp(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 (strncasecmp(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 (strcasecmp(s, "dpc") == 0) + ippAddResolution(request, IPP_TAG_JOB, option, IPP_RES_PER_CM, n, n2); + else if (strcasecmp(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... + */ + + snprintf(uri, sizeof(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 ((int)(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 [HTTP_MAX_URI] */ + char *hostname) /* O - Hostname [HTTP_MAX_URI] */ +{ + char hostbuf[HTTP_MAX_URI]; + /* Name of host */ + static char printerbuf[HTTP_MAX_URI]; + /* Name of printer or class */ + + + if (name == NULL) + { + last_error = IPP_BAD_REQUEST; + return (NULL); + } + + if (sscanf(name, "%1023[^@]@%1023s", printerbuf, hostbuf) == 1) + { + strncpy(hostbuf, cupsServer(), sizeof(hostbuf) - 1); + hostbuf[sizeof(hostbuf) - 1] = '\0'; + } + + if (hostname != NULL) + { + strncpy(hostname, hostbuf, HTTP_MAX_URI - 1); + hostname[HTTP_MAX_URI - 1] = '\0'; + } + else + hostname = hostbuf; + + if (printer != NULL) + { + strncpy(printer, printerbuf, HTTP_MAX_URI - 1); + printer[HTTP_MAX_URI - 1] = '\0'; + } + 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) + { + last_error = IPP_SERVICE_UNAVAILABLE; + return (NULL); + } + else + return (printer); +} + + +/* + * 'cups_local_auth()' - Get the local authorization certificate if + * available/applicable... + */ + +static int /* O - 1 if available, 0 if not */ +cups_local_auth(http_t *http) /* I - Connection */ +{ +#if defined(WIN32) || defined(__EMX__) + /* + * Currently WIN32 and OS-2 do not support the CUPS server... + */ + + return (0); +#else + int pid; /* Current process ID */ + FILE *fp; /* Certificate file */ + char filename[1024], /* Certificate filename */ + certificate[33]; /* Certificate string */ + + + /* + * See if we are accessing localhost... + */ + + if (ntohl(http->hostaddr.sin_addr.s_addr) != 0x7f000001 && + strcasecmp(http->hostname, "localhost") != 0) + return (0); + + /* + * Try opening a certificate file for this PID. If that fails, + * try the root certificate... + */ + + pid = getpid(); + sprintf(filename, CUPS_SERVERROOT "/certs/%d", pid); + if ((fp = fopen(filename, "r")) == NULL && pid > 0) + fp = fopen(CUPS_SERVERROOT "/certs/0", "r"); + + if (fp == NULL) + return (0); + + /* + * Read the certificate from the file... + */ + + fgets(certificate, sizeof(certificate), fp); + fclose(fp); + + /* + * Set the authorization string and return... + */ + + sprintf(authstring, "Local %s", certificate); + + return (1); +#endif /* WIN32 || __EMX__ */ +} + + +/* + * End of "$Id$". + */ diff --git a/data/8859-1 b/data/8859-1 new file mode 100644 index 0000000000..b680efc7bb --- /dev/null +++ b/data/8859-1 @@ -0,0 +1,216 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x00a1 +0xa2 0x00a2 +0xa3 0x00a3 +0xa4 0x00a4 +0xa5 0x00a5 +0xa6 0x00a6 +0xa7 0x00a7 +0xa8 0x00a8 +0xa9 0x00a9 +0xaa 0x00aa +0xab 0x00ab +0xac 0x00ac +0xad 0x00ad +0xae 0x00ae +0xaf 0x00af +0xb0 0x00b0 +0xb1 0x00b1 +0xb2 0x00b2 +0xb3 0x00b3 +0xb4 0x00b4 +0xb5 0x00b5 +0xb6 0x00b6 +0xb7 0x00b7 +0xb8 0x00b8 +0xb9 0x00b9 +0xba 0x00ba +0xbb 0x00bb +0xbc 0x00bc +0xbd 0x00bd +0xbe 0x00be +0xbf 0x00bf +0xc0 0x00c0 +0xc1 0x00c1 +0xc2 0x00c2 +0xc3 0x00c3 +0xc4 0x00c4 +0xc5 0x00c5 +0xc6 0x00c6 +0xc7 0x00c7 +0xc8 0x00c8 +0xc9 0x00c9 +0xca 0x00ca +0xcb 0x00cb +0xcc 0x00cc +0xcd 0x00cd +0xce 0x00ce +0xcf 0x00cf +0xd0 0x00d0 +0xd1 0x00d1 +0xd2 0x00d2 +0xd3 0x00d3 +0xd4 0x00d4 +0xd5 0x00d5 +0xd6 0x00d6 +0xd7 0x00d7 +0xd8 0x00d8 +0xd9 0x00d9 +0xda 0x00da +0xdb 0x00db +0xdc 0x00dc +0xdd 0x00dd +0xde 0x00de +0xdf 0x00df +0xe0 0x00e0 +0xe1 0x00e1 +0xe2 0x00e2 +0xe3 0x00e3 +0xe4 0x00e4 +0xe5 0x00e5 +0xe6 0x00e6 +0xe7 0x00e7 +0xe8 0x00e8 +0xe9 0x00e9 +0xea 0x00ea +0xeb 0x00eb +0xec 0x00ec +0xed 0x00ed +0xee 0x00ee +0xef 0x00ef +0xf0 0x00f0 +0xf1 0x00f1 +0xf2 0x00f2 +0xf3 0x00f3 +0xf4 0x00f4 +0xf5 0x00f5 +0xf6 0x00f6 +0xf7 0x00f7 +0xf8 0x00f8 +0xf9 0x00f9 +0xfa 0x00fa +0xfb 0x00fb +0xfc 0x00fc +0xfd 0x00fd +0xfe 0x00fe +0xff 0x00ff diff --git a/data/8859-14 b/data/8859-14 new file mode 100644 index 0000000000..648be60bff --- /dev/null +++ b/data/8859-14 @@ -0,0 +1,217 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x1e02 +0xa2 0x1e03 +0xa3 0x00a3 +0xa4 0x010a +0xa5 0x010b +0xa6 0x1e0a +0xa7 0x00a7 +0xa8 0x1e80 +0xa9 0x00a9 +0xaa 0x1e82 +0xab 0x1e0b +0xac 0x1ef2 +0xad 0x00ad +0xae 0x00ae +0xaf 0x0178 +0xb0 0x1e1e +0xb1 0x1e1f +0xb2 0x0120 +0xb3 0x0121 +0xb4 0x1e40 +0xb5 0x1e41 +0xb6 0x00b6 +0xb7 0x1e56 +0xb8 0x1e81 +0xb9 0x1e57 +0xba 0x1e83 +0xbb 0x1e60 +0xbc 0x1ef3 +0xbd 0x1e84 +0xbe 0x1e85 +0xbf 0x1e61 +0xc0 0x00c0 +0xc1 0x00c1 +0xc2 0x00c2 +0xc3 0x00c3 +0xc4 0x00c4 +0xc5 0x00c5 +0xc6 0x00c6 +0xc7 0x00c7 +0xc8 0x00c8 +0xc9 0x00c9 +0xca 0x00ca +0xcb 0x00cb +0xcc 0x00cc +0xcd 0x00cd +0xce 0x00ce +0xcf 0x00cf +0xd0 0x0174 +0xd1 0x00d1 +0xd2 0x00d2 +0xd3 0x00d3 +0xd4 0x00d4 +0xd5 0x00d5 +0xd6 0x00d6 +0xd7 0x1e6a +0xd8 0x00d8 +0xd9 0x00d9 +0xda 0x00da +0xdb 0x00db +0xdc 0x00dc +0xdd 0x00dd +0xde 0x0176 +0xdf 0x00df +0xe0 0x00e0 +0xe1 0x00e1 +0xe2 0x00e2 +0xe3 0x00e3 +0xe4 0x00e4 +0xe5 0x00e5 +0xe6 0x00e6 +0xe7 0x00e7 +0xe8 0x00e8 +0xe9 0x00e9 +0xea 0x00ea +0xeb 0x00eb +0xec 0x00ec +0xed 0x00ed +0xee 0x00ee +0xef 0x00ef +0xf0 0x0175 +0xf1 0x00f1 +0xf2 0x00f2 +0xf3 0x00f3 +0xf4 0x00f4 +0xf5 0x00f5 +0xf6 0x00f6 +0xf7 0x1e6b +0xf8 0x00f8 +0xf9 0x00f9 +0xfa 0x00fa +0xfb 0x00fb +0xfc 0x00fc +0xfd 0x00fd +0xfe 0x0177 +0xff 0x00ff + diff --git a/data/8859-15 b/data/8859-15 new file mode 100644 index 0000000000..fa50e1e74a --- /dev/null +++ b/data/8859-15 @@ -0,0 +1,217 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x00a1 +0xa2 0x00a2 +0xa3 0x00a3 +0xa4 0x20ac +0xa5 0x00a5 +0xa6 0x0160 +0xa7 0x00a7 +0xa8 0x0161 +0xa9 0x00a9 +0xaa 0x00aa +0xab 0x00ab +0xac 0x00ac +0xad 0x00ad +0xae 0x00ae +0xaf 0x00af +0xb0 0x00b0 +0xb1 0x00b1 +0xb2 0x00b2 +0xb3 0x00b3 +0xb4 0x017d +0xb5 0x00b5 +0xb6 0x00b6 +0xb7 0x00b7 +0xb8 0x017e +0xb9 0x00b9 +0xba 0x00ba +0xbb 0x00bb +0xbc 0x0152 +0xbd 0x0153 +0xbe 0x0178 +0xbf 0x00bf +0xc0 0x00c0 +0xc1 0x00c1 +0xc2 0x00c2 +0xc3 0x00c3 +0xc4 0x00c4 +0xc5 0x00c5 +0xc6 0x00c6 +0xc7 0x00c7 +0xc8 0x00c8 +0xc9 0x00c9 +0xca 0x00ca +0xcb 0x00cb +0xcc 0x00cc +0xcd 0x00cd +0xce 0x00ce +0xcf 0x00cf +0xd0 0x00d0 +0xd1 0x00d1 +0xd2 0x00d2 +0xd3 0x00d3 +0xd4 0x00d4 +0xd5 0x00d5 +0xd6 0x00d6 +0xd7 0x00d7 +0xd8 0x00d8 +0xd9 0x00d9 +0xda 0x00da +0xdb 0x00db +0xdc 0x00dc +0xdd 0x00dd +0xde 0x00de +0xdf 0x00df +0xe0 0x00e0 +0xe1 0x00e1 +0xe2 0x00e2 +0xe3 0x00e3 +0xe4 0x00e4 +0xe5 0x00e5 +0xe6 0x00e6 +0xe7 0x00e7 +0xe8 0x00e8 +0xe9 0x00e9 +0xea 0x00ea +0xeb 0x00eb +0xec 0x00ec +0xed 0x00ed +0xee 0x00ee +0xef 0x00ef +0xf0 0x00f0 +0xf1 0x00f1 +0xf2 0x00f2 +0xf3 0x00f3 +0xf4 0x00f4 +0xf5 0x00f5 +0xf6 0x00f6 +0xf7 0x00f7 +0xf8 0x00f8 +0xf9 0x00f9 +0xfa 0x00fa +0xfb 0x00fb +0xfc 0x00fc +0xfd 0x00fd +0xfe 0x00fe +0xff 0x00ff + diff --git a/data/8859-2 b/data/8859-2 new file mode 100644 index 0000000000..29a753b624 --- /dev/null +++ b/data/8859-2 @@ -0,0 +1,218 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x015a +0x8d 0x0164 +0x8e 0x017d +0x8f 0x0179 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x8c 0x015b +0x8d 0x0165 +0x8e 0x017e +0x8f 0x017a +0xa0 0x00a0 +0xa1 0x0104 +0xa2 0x02d8 +0xa3 0x0141 +0xa4 0x00a4 +0xa5 0x013d +0xa6 0x015a +0xa7 0x00a7 +0xa8 0x00a8 +0xa9 0x0160 +0xaa 0x015e +0xab 0x0164 +0xac 0x0179 +0xad 0x00ad +0xae 0x017d +0xaf 0x017b +0xb0 0x00b0 +0xb1 0x0105 +0xb2 0x02db +0xb3 0x0142 +0xb4 0x00b4 +0xb5 0x013e +0xb6 0x015b +0xb7 0x02c7 +0xb8 0x00b8 +0xb9 0x0161 +0xba 0x015f +0xbb 0x0165 +0xbc 0x017a +0xbd 0x02dd +0xbe 0x017e +0xbf 0x017c +0xc0 0x0154 +0xc1 0x00c1 +0xc2 0x00c2 +0xc3 0x0102 +0xc4 0x00c4 +0xc5 0x0139 +0xc6 0x0106 +0xc7 0x00c7 +0xc8 0x010c +0xc9 0x00c9 +0xca 0x0118 +0xcb 0x00cb +0xcc 0x011a +0xcd 0x00cd +0xce 0x00ce +0xcf 0x010e +0xd0 0x0110 +0xd1 0x0143 +0xd2 0x0147 +0xd3 0x00d3 +0xd4 0x00d4 +0xd5 0x0150 +0xd6 0x00d6 +0xd7 0x00d7 +0xd8 0x0158 +0xd9 0x016e +0xda 0x00da +0xdb 0x0170 +0xdc 0x00dc +0xdd 0x00dd +0xde 0x0162 +0xdf 0x00df +0xe0 0x0155 +0xe1 0x00e1 +0xe2 0x00e2 +0xe3 0x0103 +0xe4 0x00e4 +0xe5 0x013a +0xe6 0x0107 +0xe7 0x00e7 +0xe8 0x010d +0xe9 0x00e9 +0xea 0x0119 +0xeb 0x00eb +0xec 0x011b +0xed 0x00ed +0xee 0x00ee +0xef 0x010f +0xf0 0x0111 +0xf1 0x0144 +0xf2 0x0148 +0xf3 0x00f3 +0xf4 0x00f4 +0xf5 0x0151 +0xf6 0x00f6 +0xf7 0x00f7 +0xf8 0x0159 +0xf9 0x016f +0xfa 0x00fa +0xfb 0x0171 +0xfc 0x00fc +0xfd 0x00fd +0xfe 0x0163 +0xff 0x02d9 diff --git a/data/8859-3 b/data/8859-3 new file mode 100644 index 0000000000..c0c4588023 --- /dev/null +++ b/data/8859-3 @@ -0,0 +1,209 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x0126 +0xa2 0x02d8 +0xa3 0x00a3 +0xa4 0x00a4 +0xa6 0x0124 +0xa7 0x00a7 +0xa8 0x00a8 +0xa9 0x0130 +0xaa 0x015e +0xab 0x011e +0xac 0x0134 +0xad 0x00ad +0xaf 0x017b +0xb0 0x00b0 +0xb1 0x0127 +0xb2 0x00b2 +0xb3 0x00b3 +0xb4 0x00b4 +0xb5 0x00b5 +0xb6 0x0125 +0xb7 0x00b7 +0xb8 0x00b8 +0xb9 0x0131 +0xba 0x015f +0xbb 0x011f +0xbc 0x0135 +0xbd 0x00bd +0xbf 0x017c +0xc0 0x00c0 +0xc1 0x00c1 +0xc2 0x00c2 +0xc4 0x00c4 +0xc5 0x010a +0xc6 0x0108 +0xc7 0x00c7 +0xc8 0x00c8 +0xc9 0x00c9 +0xca 0x00ca +0xcb 0x00cb +0xcc 0x00cc +0xcd 0x00cd +0xce 0x00ce +0xcf 0x00cf +0xd1 0x00d1 +0xd2 0x00d2 +0xd3 0x00d3 +0xd4 0x00d4 +0xd5 0x0120 +0xd6 0x00d6 +0xd7 0x00d7 +0xd8 0x011c +0xd9 0x00d9 +0xda 0x00da +0xdb 0x00db +0xdc 0x00dc +0xdd 0x016c +0xde 0x015c +0xdf 0x00df +0xe0 0x00e0 +0xe1 0x00e1 +0xe2 0x00e2 +0xe4 0x00e4 +0xe5 0x010b +0xe6 0x0109 +0xe7 0x00e7 +0xe8 0x00e8 +0xe9 0x00e9 +0xea 0x00ea +0xeb 0x00eb +0xec 0x00ec +0xed 0x00ed +0xee 0x00ee +0xef 0x00ef +0xf1 0x00f1 +0xf2 0x00f2 +0xf3 0x00f3 +0xf4 0x00f4 +0xf5 0x0121 +0xf6 0x00f6 +0xf7 0x00f7 +0xf8 0x011d +0xf9 0x00f9 +0xfa 0x00fa +0xfb 0x00fb +0xfc 0x00fc +0xfd 0x016d +0xfe 0x015d +0xff 0x02d9 diff --git a/data/8859-4 b/data/8859-4 new file mode 100644 index 0000000000..b5accea386 --- /dev/null +++ b/data/8859-4 @@ -0,0 +1,216 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x0104 +0xa2 0x0138 +0xa3 0x0156 +0xa4 0x00a4 +0xa5 0x0128 +0xa6 0x013b +0xa7 0x00a7 +0xa8 0x00a8 +0xa9 0x0160 +0xaa 0x0112 +0xab 0x0122 +0xac 0x0166 +0xad 0x00ad +0xae 0x017d +0xaf 0x00af +0xb0 0x00b0 +0xb1 0x0105 +0xb2 0x02db +0xb3 0x0157 +0xb4 0x00b4 +0xb5 0x0129 +0xb6 0x013c +0xb7 0x02c7 +0xb8 0x00b8 +0xb9 0x0161 +0xba 0x0113 +0xbb 0x0123 +0xbc 0x0167 +0xbd 0x014a +0xbe 0x017e +0xbf 0x014b +0xc0 0x0100 +0xc1 0x00c1 +0xc2 0x00c2 +0xc3 0x00c3 +0xc4 0x00c4 +0xc5 0x00c5 +0xc6 0x00c6 +0xc7 0x012e +0xc8 0x010c +0xc9 0x00c9 +0xca 0x0118 +0xcb 0x00cb +0xcc 0x0116 +0xcd 0x00cd +0xce 0x00ce +0xcf 0x012a +0xd0 0x0110 +0xd1 0x0145 +0xd2 0x014c +0xd3 0x0136 +0xd4 0x00d4 +0xd5 0x00d5 +0xd6 0x00d6 +0xd7 0x00d7 +0xd8 0x00d8 +0xd9 0x0172 +0xda 0x00da +0xdb 0x00db +0xdc 0x00dc +0xdd 0x0168 +0xde 0x016a +0xdf 0x00df +0xe0 0x0101 +0xe1 0x00e1 +0xe2 0x00e2 +0xe3 0x00e3 +0xe4 0x00e4 +0xe5 0x00e5 +0xe6 0x00e6 +0xe7 0x012f +0xe8 0x010d +0xe9 0x00e9 +0xea 0x0119 +0xeb 0x00eb +0xec 0x0117 +0xed 0x00ed +0xee 0x00ee +0xef 0x012b +0xf0 0x0111 +0xf1 0x0146 +0xf2 0x014d +0xf3 0x0137 +0xf4 0x00f4 +0xf5 0x00f5 +0xf6 0x00f6 +0xf7 0x00f7 +0xf8 0x00f8 +0xf9 0x0173 +0xfa 0x00fa +0xfb 0x00fb +0xfc 0x00fc +0xfd 0x0169 +0xfe 0x016b +0xff 0x02d9 diff --git a/data/8859-5 b/data/8859-5 new file mode 100644 index 0000000000..919b55d09b --- /dev/null +++ b/data/8859-5 @@ -0,0 +1,216 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x0401 +0xa2 0x0402 +0xa3 0x0403 +0xa4 0x0404 +0xa5 0x0405 +0xa6 0x0406 +0xa7 0x0407 +0xa8 0x0408 +0xa9 0x0409 +0xaa 0x040a +0xab 0x040b +0xac 0x040c +0xad 0x00ad +0xae 0x040e +0xaf 0x040f +0xb0 0x0410 +0xb1 0x0411 +0xb2 0x0412 +0xb3 0x0413 +0xb4 0x0414 +0xb5 0x0415 +0xb6 0x0416 +0xb7 0x0417 +0xb8 0x0418 +0xb9 0x0419 +0xba 0x041a +0xbb 0x041b +0xbc 0x041c +0xbd 0x041d +0xbe 0x041e +0xbf 0x041f +0xc0 0x0420 +0xc1 0x0421 +0xc2 0x0422 +0xc3 0x0423 +0xc4 0x0424 +0xc5 0x0425 +0xc6 0x0426 +0xc7 0x0427 +0xc8 0x0428 +0xc9 0x0429 +0xca 0x042a +0xcb 0x042b +0xcc 0x042c +0xcd 0x042d +0xce 0x042e +0xcf 0x042f +0xd0 0x0430 +0xd1 0x0431 +0xd2 0x0432 +0xd3 0x0433 +0xd4 0x0434 +0xd5 0x0435 +0xd6 0x0436 +0xd7 0x0437 +0xd8 0x0438 +0xd9 0x0439 +0xda 0x043a +0xdb 0x043b +0xdc 0x043c +0xdd 0x043d +0xde 0x043e +0xdf 0x043f +0xe0 0x0440 +0xe1 0x0441 +0xe2 0x0442 +0xe3 0x0443 +0xe4 0x0444 +0xe5 0x0445 +0xe6 0x0446 +0xe7 0x0447 +0xe8 0x0448 +0xe9 0x0449 +0xea 0x044a +0xeb 0x044b +0xec 0x044c +0xed 0x044d +0xee 0x044e +0xef 0x044f +0xf0 0x2116 +0xf1 0x0451 +0xf2 0x0452 +0xf3 0x0453 +0xf4 0x0454 +0xf5 0x0455 +0xf6 0x0456 +0xf7 0x0457 +0xf8 0x0458 +0xf9 0x0459 +0xfa 0x045a +0xfb 0x045b +0xfc 0x045c +0xfd 0x00a7 +0xfe 0x045e +0xff 0x045f diff --git a/data/8859-6 b/data/8859-6 new file mode 100644 index 0000000000..90b7d49172 --- /dev/null +++ b/data/8859-6 @@ -0,0 +1,171 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0660 +0x31 0x0661 +0x32 0x0662 +0x33 0x0663 +0x34 0x0664 +0x35 0x0665 +0x36 0x0666 +0x37 0x0667 +0x38 0x0668 +0x39 0x0669 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa4 0x00a4 +0xac 0x060c +0xad 0x00ad +0xbb 0x061b +0xbf 0x061f +0xc1 0x0621 +0xc2 0x0622 +0xc3 0x0623 +0xc4 0x0624 +0xc5 0x0625 +0xc6 0x0626 +0xc7 0x0627 +0xc8 0x0628 +0xc9 0x0629 +0xca 0x062a +0xcb 0x062b +0xcc 0x062c +0xcd 0x062d +0xce 0x062e +0xcf 0x062f +0xd0 0x0630 +0xd1 0x0631 +0xd2 0x0632 +0xd3 0x0633 +0xd4 0x0634 +0xd5 0x0635 +0xd6 0x0636 +0xd7 0x0637 +0xd8 0x0638 +0xd9 0x0639 +0xda 0x063a +0xe0 0x0640 +0xe1 0x0641 +0xe2 0x0642 +0xe3 0x0643 +0xe4 0x0644 +0xe5 0x0645 +0xe6 0x0646 +0xe7 0x0647 +0xe8 0x0648 +0xe9 0x0649 +0xea 0x064a +0xeb 0x064b +0xec 0x064c +0xed 0x064d +0xee 0x064e +0xef 0x064f +0xf0 0x0650 +0xf1 0x0651 +0xf2 0x0652 diff --git a/data/8859-7 b/data/8859-7 new file mode 100644 index 0000000000..56502dac7f --- /dev/null +++ b/data/8859-7 @@ -0,0 +1,210 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x02bd +0xa2 0x02bc +0xa3 0x00a3 +0xa6 0x00a6 +0xa7 0x00a7 +0xa8 0x00a8 +0xa9 0x00a9 +0xab 0x00ab +0xac 0x00ac +0xad 0x00ad +0xaf 0x2015 +0xb0 0x00b0 +0xb1 0x00b1 +0xb2 0x00b2 +0xb3 0x00b3 +0xb4 0x0384 +0xb5 0x0385 +0xb6 0x0386 +0xb7 0x00b7 +0xb8 0x0388 +0xb9 0x0389 +0xba 0x038a +0xbb 0x00bb +0xbc 0x038c +0xbd 0x00bd +0xbe 0x038e +0xbf 0x038f +0xc0 0x0390 +0xc1 0x0391 +0xc2 0x0392 +0xc3 0x0393 +0xc4 0x0394 +0xc5 0x0395 +0xc6 0x0396 +0xc7 0x0397 +0xc8 0x0398 +0xc9 0x0399 +0xca 0x039a +0xcb 0x039b +0xcc 0x039c +0xcd 0x039d +0xce 0x039e +0xcf 0x039f +0xd0 0x03a0 +0xd1 0x03a1 +0xd3 0x03a3 +0xd4 0x03a4 +0xd5 0x03a5 +0xd6 0x03a6 +0xd7 0x03a7 +0xd8 0x03a8 +0xd9 0x03a9 +0xda 0x03aa +0xdb 0x03ab +0xdc 0x03ac +0xdd 0x03ad +0xde 0x03ae +0xdf 0x03af +0xe0 0x03b0 +0xe1 0x03b1 +0xe2 0x03b2 +0xe3 0x03b3 +0xe4 0x03b4 +0xe5 0x03b5 +0xe6 0x03b6 +0xe7 0x03b7 +0xe8 0x03b8 +0xe9 0x03b9 +0xea 0x03ba +0xeb 0x03bb +0xec 0x03bc +0xed 0x03bd +0xee 0x03be +0xef 0x03bf +0xf0 0x03c0 +0xf1 0x03c1 +0xf2 0x03c2 +0xf3 0x03c3 +0xf4 0x03c4 +0xf5 0x03c5 +0xf6 0x03c6 +0xf7 0x03c7 +0xf8 0x03c8 +0xf9 0x03c9 +0xfa 0x03ca +0xfb 0x03cb +0xfc 0x03cc +0xfd 0x03cd +0xfe 0x03ce diff --git a/data/8859-8 b/data/8859-8 new file mode 100644 index 0000000000..c1c0f657c3 --- /dev/null +++ b/data/8859-8 @@ -0,0 +1,178 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa2 0x00a2 +0xa3 0x00a3 +0xa4 0x00a4 +0xa5 0x00a5 +0xa6 0x00a6 +0xa7 0x00a7 +0xa8 0x00a8 +0xa9 0x00a9 +0xaa 0x00d7 +0xab 0x00ab +0xac 0x00ac +0xad 0x00ad +0xae 0x00ae +0xaf 0x203e +0xb0 0x00b0 +0xb1 0x00b1 +0xb2 0x00b2 +0xb3 0x00b3 +0xb4 0x00b4 +0xb5 0x00b5 +0xb6 0x00b6 +0xb7 0x00b7 +0xb8 0x00b8 +0xb9 0x00b9 +0xba 0x00f7 +0xbb 0x00bb +0xbc 0x00bc +0xbd 0x00bd +0xbe 0x00be +0xdf 0x2017 +0xe0 0x05d0 +0xe1 0x05d1 +0xe2 0x05d2 +0xe3 0x05d3 +0xe4 0x05d4 +0xe5 0x05d5 +0xe6 0x05d6 +0xe7 0x05d7 +0xe8 0x05d8 +0xe9 0x05d9 +0xea 0x05da +0xeb 0x05db +0xec 0x05dc +0xed 0x05dd +0xee 0x05de +0xef 0x05df +0xf0 0x05e0 +0xf1 0x05e1 +0xf2 0x05e2 +0xf3 0x05e3 +0xf4 0x05e4 +0xf5 0x05e5 +0xf6 0x05e6 +0xf7 0x05e7 +0xf8 0x05e8 +0xf9 0x05e9 +0xfa 0x05ea diff --git a/data/8859-9 b/data/8859-9 new file mode 100644 index 0000000000..1cc08eb442 --- /dev/null +++ b/data/8859-9 @@ -0,0 +1,218 @@ +0x20 0x0020 +0x21 0x0021 +0x22 0x0022 +0x23 0x0023 +0x24 0x0024 +0x25 0x0025 +0x26 0x0026 +0x27 0x0027 +0x28 0x0028 +0x29 0x0029 +0x2a 0x002a +0x2b 0x002b +0x2c 0x002c +0x2d 0x002d +0x2e 0x002e +0x2f 0x002f +0x30 0x0030 +0x31 0x0031 +0x32 0x0032 +0x33 0x0033 +0x34 0x0034 +0x35 0x0035 +0x36 0x0036 +0x37 0x0037 +0x38 0x0038 +0x39 0x0039 +0x3a 0x003a +0x3b 0x003b +0x3c 0x003c +0x3d 0x003d +0x3e 0x003e +0x3f 0x003f +0x40 0x0040 +0x41 0x0041 +0x42 0x0042 +0x43 0x0043 +0x44 0x0044 +0x45 0x0045 +0x46 0x0046 +0x47 0x0047 +0x48 0x0048 +0x49 0x0049 +0x4a 0x004a +0x4b 0x004b +0x4c 0x004c +0x4d 0x004d +0x4e 0x004e +0x4f 0x004f +0x50 0x0050 +0x51 0x0051 +0x52 0x0052 +0x53 0x0053 +0x54 0x0054 +0x55 0x0055 +0x56 0x0056 +0x57 0x0057 +0x58 0x0058 +0x59 0x0059 +0x5a 0x005a +0x5b 0x005b +0x5c 0x005c +0x5d 0x005d +0x5e 0x005e +0x5f 0x005f +0x60 0x0060 +0x61 0x0061 +0x62 0x0062 +0x63 0x0063 +0x64 0x0064 +0x65 0x0065 +0x66 0x0066 +0x67 0x0067 +0x68 0x0068 +0x69 0x0069 +0x6a 0x006a +0x6b 0x006b +0x6c 0x006c +0x6d 0x006d +0x6e 0x006e +0x6f 0x006f +0x70 0x0070 +0x71 0x0071 +0x72 0x0072 +0x73 0x0073 +0x74 0x0074 +0x75 0x0075 +0x76 0x0076 +0x77 0x0077 +0x78 0x0078 +0x79 0x0079 +0x7a 0x007a +0x7b 0x007b +0x7c 0x007c +0x7d 0x007d +0x7e 0x007e +0x80 0x20ac +0x82 0x201a +0x83 0x0192 +0x84 0x201e +0x85 0x2026 +0x86 0x2020 +0x87 0x2021 +0x88 0x02c6 +0x89 0x2030 +0x8a 0x0160 +0x8b 0x2039 +0x8c 0x0152 +0x91 0x2018 +0x92 0x2019 +0x93 0x201c +0x94 0x201d +0x95 0x2022 +0x96 0x2013 +0x97 0x2014 +0x98 0x02dc +0x99 0x2122 +0x9a 0x0161 +0x9b 0x203a +0x9c 0x0153 +0x9f 0x0178 +0xa0 0x00a0 +0xa1 0x00a1 +0xa2 0x00a2 +0xa3 0x00a3 +0xa4 0x00a4 +0xa5 0x00a5 +0xa6 0x00a6 +0xa7 0x00a7 +0xa8 0x00a8 +0xa9 0x00a9 +0xaa 0x00aa +0xab 0x00ab +0xac 0x00ac +0xad 0x00ad +0xae 0x00ae +0xaf 0x00af +0xb0 0x00b0 +0xb1 0x00b1 +0xb2 0x00b2 +0xb3 0x00b3 +0xb4 0x00b4 +0xb5 0x00b5 +0xb6 0x00b6 +0xb7 0x00b7 +0xb8 0x00b8 +0xb9 0x00b9 +0xba 0x00ba +0xbb 0x00bb +0xbc 0x00bc +0xbd 0x00bd +0xbe 0x00be +0xbf 0x00bf +0xc0 0x00c0 +0xc1 0x00c1 +0xc2 0x00c2 +0xc3 0x00c3 +0xc4 0x00c4 +0xc5 0x00c5 +0xc6 0x00c6 +0xc7 0x00c7 +0xc8 0x00c8 +0xc9 0x00c9 +0xca 0x00ca +0xcb 0x00cb +0xcc 0x00cc +0xcd 0x00cd +0xce 0x00ce +0xcf 0x00cf +0xd0 0x011e +0xd1 0x00d1 +0xd2 0x00d2 +0xd3 0x00d3 +0xd4 0x00d4 +0xd5 0x00d5 +0xd6 0x00d6 +0xd7 0x00d7 +0xd8 0x00d8 +0xd9 0x00d9 +0xda 0x00da +0xdb 0x00db +0xdc 0x00dc +0xdd 0x0130 +0xde 0x015e +0xdf 0x00df +0xe0 0x00e0 +0xe1 0x00e1 +0xe2 0x00e2 +0xe3 0x00e3 +0xe4 0x00e4 +0xe5 0x00e5 +0xe6 0x00e6 +0xe7 0x00e7 +0xe8 0x00e8 +0xe9 0x00e9 +0xea 0x00ea +0xeb 0x00eb +0xec 0x00ec +0xed 0x00ed +0xee 0x00ee +0xef 0x00ef +0xf0 0x011f +0xf1 0x00f1 +0xf2 0x00f2 +0xf3 0x00f3 +0xf4 0x00f4 +0xf5 0x00f5 +0xf6 0x00f6 +0xf7 0x00f7 +0xf8 0x00f8 +0xf9 0x00f9 +0xfa 0x00fa +0xfb 0x00fb +0xfc 0x00fc +0xfd 0x0131 +0xfe 0x015f +0xff 0x00ff + + diff --git a/data/HPGLprolog b/data/HPGLprolog new file mode 100644 index 0000000000..21b244ca23 --- /dev/null +++ b/data/HPGLprolog @@ -0,0 +1,37 @@ +%%BeginResource: procset hpgltops 1.1 0 +% +% "$Id: HPGLprolog 932 2000-02-26 20:01:37Z mike $" +% +% HP-GL/2 filter procset for the Common UNIX Printing System (CUPS). +% +% This procset contains the basic drawing commands that are used to +% reduce output size. Note the 'MP' (make newpath) definition - this +% should be called 'NP' (newpath), but GhostScript uses the 'NP' name +% for 'noaccess put' in some of its font files... +% +% Copyright 1993-2000 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 +% +/MO { moveto } bind def +/LI { lineto } bind def +/FI { fill } bind def +/ST { stroke } bind def +/CP { closepath } bind def +/MP { newpath } bind def +/SP { setlinewidth setrgbcolor } bind def +%%EndResource diff --git a/data/Makefile b/data/Makefile new file mode 100644 index 0000000000..b19c3f50e9 --- /dev/null +++ b/data/Makefile @@ -0,0 +1,86 @@ +# +# "$Id$" +# +# Datafile makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2000 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... +# + +CHARSETS = cp874 \ + cp1250 \ + cp1251 \ + cp1252 \ + cp1253 \ + cp1254 \ + cp1255 \ + cp1256 \ + cp1257 \ + cp1258 \ + 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-10 \ + iso-8859-13 \ + iso-8859-14 \ + iso-8859-15 \ + utf-8 +DATAFILES = HPGLprolog psglyphs testprint.ps + + +# +# Make everything... +# + +all: + + +# +# Clean all config and object files... +# + +clean: + + +# +# Install files... +# + +install: + -$(MKDIR) $(DATADIR) + -$(MKDIR) $(DATADIR)/data + $(CP) $(DATAFILES) $(DATADIR)/data + -$(MKDIR) $(DATADIR)/charsets + $(CP) $(CHARSETS) $(DATADIR)/charsets + + +# +# End of "$Id$". +# diff --git a/data/cp1250 b/data/cp1250 new file mode 100644 index 0000000000..1e42b2d074 --- /dev/null +++ b/data/cp1250 @@ -0,0 +1,254 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1250 (WinLatin2) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8A 0160 +8B 2039 +8C 015A +8D 0164 +8E 017D +8F 0179 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9A 0161 +9B 203A +9C 015B +9D 0165 +9E 017E +9F 017A +A0 00A0 +A1 02C7 +A2 02D8 +A3 0141 +A4 00A4 +A5 0104 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 015E +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 017B +B0 00B0 +B1 00B1 +B2 02DB +B3 0142 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 0105 +BA 015F +BB 00BB +BC 013D +BD 02DD +BE 013E +BF 017C +C0 0154 +C1 00C1 +C2 00C2 +C3 0102 +C4 00C4 +C5 0139 +C6 0106 +C7 00C7 +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 011A +CD 00CD +CE 00CE +CF 010E +D0 0110 +D1 0143 +D2 0147 +D3 00D3 +D4 00D4 +D5 0150 +D6 00D6 +D7 00D7 +D8 0158 +D9 016E +DA 00DA +DB 0170 +DC 00DC +DD 00DD +DE 0162 +DF 00DF +E0 0155 +E1 00E1 +E2 00E2 +E3 0103 +E4 00E4 +E5 013A +E6 0107 +E7 00E7 +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 011B +ED 00ED +EE 00EE +EF 010F +F0 0111 +F1 0144 +F2 0148 +F3 00F3 +F4 00F4 +F5 0151 +F6 00F6 +F7 00F7 +F8 0159 +F9 016F +FA 00FA +FB 0171 +FC 00FC +FD 00FD +FE 0163 +FF 02D9 diff --git a/data/cp1251 b/data/cp1251 new file mode 100644 index 0000000000..27639087b8 --- /dev/null +++ b/data/cp1251 @@ -0,0 +1,258 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1251 (WinCyrillic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 0402 +81 0403 +82 201A +83 0453 +84 201E +85 2026 +86 2020 +87 2021 +88 20AC +89 2030 +8A 0409 +8B 2039 +8C 040A +8D 040C +8E 040B +8F 040F +90 0452 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9A 0459 +9B 203A +9C 045A +9D 045C +9E 045B +9F 045F +A0 00A0 +A1 040E +A2 045E +A3 0408 +A4 00A4 +A5 0490 +A6 00A6 +A7 00A7 +A8 0401 +A9 00A9 +AA 0404 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 0407 +B0 00B0 +B1 00B1 +B2 0406 +B3 0456 +B4 0491 +B5 00B5 +B6 00B6 +B7 00B7 +B8 0451 +B9 2116 +BA 0454 +BB 00BB +BC 0458 +BD 0405 +BE 0455 +BF 0457 +C0 0410 +C1 0411 +C2 0412 +C3 0413 +C4 0414 +C5 0415 +C6 0416 +C7 0417 +C8 0418 +C9 0419 +CA 041A +CB 041B +CC 041C +CD 041D +CE 041E +CF 041F +D0 0420 +D1 0421 +D2 0422 +D3 0423 +D4 0424 +D5 0425 +D6 0426 +D7 0427 +D8 0428 +D9 0429 +DA 042A +DB 042B +DC 042C +DD 042D +DE 042E +DF 042F +E0 0430 +E1 0431 +E2 0432 +E3 0433 +E4 0434 +E5 0435 +E6 0436 +E7 0437 +E8 0438 +E9 0439 +EA 043A +EB 043B +EC 043C +ED 043D +EE 043E +EF 043F +F0 0440 +F1 0441 +F2 0442 +F3 0443 +F4 0444 +F5 0445 +F6 0446 +F7 0447 +F8 0448 +F9 0449 +FA 044A +FB 044B +FC 044C +FD 044D +FE 044E +FF 044F diff --git a/data/cp1252 b/data/cp1252 new file mode 100644 index 0000000000..93601c9dbc --- /dev/null +++ b/data/cp1252 @@ -0,0 +1,254 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1252 (WinLatin1) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +8E 017D +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9E 017E +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 00D0 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FE +FF 00FF diff --git a/data/cp1253 b/data/cp1253 new file mode 100644 index 0000000000..adb8c2e88d --- /dev/null +++ b/data/cp1253 @@ -0,0 +1,242 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1253 (WinGreek) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8B 2039 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9B 203A +A0 00A0 +A1 0385 +A2 0386 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 2015 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 0384 +B5 00B5 +B6 00B6 +B7 00B7 +B8 0388 +B9 0389 +BA 038A +BB 00BB +BC 038C +BD 00BD +BE 038E +BF 038F +C0 0390 +C1 0391 +C2 0392 +C3 0393 +C4 0394 +C5 0395 +C6 0396 +C7 0397 +C8 0398 +C9 0399 +CA 039A +CB 039B +CC 039C +CD 039D +CE 039E +CF 039F +D0 03A0 +D1 03A1 +D3 03A3 +D4 03A4 +D5 03A5 +D6 03A6 +D7 03A7 +D8 03A8 +D9 03A9 +DA 03AA +DB 03AB +DC 03AC +DD 03AD +DE 03AE +DF 03AF +E0 03B0 +E1 03B1 +E2 03B2 +E3 03B3 +E4 03B4 +E5 03B5 +E6 03B6 +E7 03B7 +E8 03B8 +E9 03B9 +EA 03BA +EB 03BB +EC 03BC +ED 03BD +EE 03BE +EF 03BF +F0 03C0 +F1 03C1 +F2 03C2 +F3 03C3 +F4 03C4 +F5 03C5 +F6 03C6 +F7 03C7 +F8 03C8 +F9 03C9 +FA 03CA +FB 03CB +FC 03CC +FD 03CD +FE 03CE diff --git a/data/cp1254 b/data/cp1254 new file mode 100644 index 0000000000..19e28148c3 --- /dev/null +++ b/data/cp1254 @@ -0,0 +1,252 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1254 (WinTurkish) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 011E +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 0130 +DE 015E +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 011F +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 0131 +FE 015F +FF 00FF diff --git a/data/cp1255 b/data/cp1255 new file mode 100644 index 0000000000..1d74ba8691 --- /dev/null +++ b/data/cp1255 @@ -0,0 +1,236 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1255 (WinHebrew) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +rtol single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8B 2039 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9B 203A +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 20AA +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00D7 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00F7 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 05B0 +C1 05B1 +C2 05B2 +C3 05B3 +C4 05B4 +C5 05B5 +C6 05B6 +C7 05B7 +C8 05B8 +C9 05B9 +CB 05BB +CC 05BC +CD 05BD +CE 05BE +CF 05BF +D0 05C0 +D1 05C1 +D2 05C2 +D3 05C3 +D4 05F0 +D5 05F1 +D6 05F2 +D7 05F3 +D8 05F4 +E0 05D0 +E1 05D1 +E2 05D2 +E3 05D3 +E4 05D4 +E5 05D5 +E6 05D6 +E7 05D7 +E8 05D8 +E9 05D9 +EA 05DA +EB 05DB +EC 05DC +ED 05DD +EE 05DE +EF 05DF +F0 05E0 +F1 05E1 +F2 05E2 +F3 05E3 +F4 05E4 +F5 05E5 +F6 05E6 +F7 05E7 +F8 05E8 +F9 05E9 +FA 05EA +FD 200E +FE 200F diff --git a/data/cp1256 b/data/cp1256 new file mode 100644 index 0000000000..10382901f1 --- /dev/null +++ b/data/cp1256 @@ -0,0 +1,259 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1256 (WinArabic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +rtol single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +81 067E +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0679 +8B 2039 +8C 0152 +8D 0686 +8E 0698 +8F 0688 +90 06AF +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 06A9 +99 2122 +9A 0691 +9B 203A +9C 0153 +9D 200C +9E 200D +9F 06BA +A0 00A0 +A1 060C +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 06BE +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 061B +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 061F +C0 06C1 +C1 0621 +C2 0622 +C3 0623 +C4 0624 +C5 0625 +C6 0626 +C7 0627 +C8 0628 +C9 0629 +CA 062A +CB 062B +CC 062C +CD 062D +CE 062E +CF 062F +D0 0630 +D1 0631 +D2 0632 +D3 0633 +D4 0634 +D5 0635 +D6 0636 +D7 00D7 +D8 0637 +D9 0638 +DA 0639 +DB 063A +DC 0640 +DD 0641 +DE 0642 +DF 0643 +E0 00E0 +E1 0644 +E2 00E2 +E3 0645 +E4 0646 +E5 0647 +E6 0648 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 0649 +ED 064A +EE 00EE +EF 00EF +F0 064B +F1 064C +F2 064D +F3 064E +F4 00F4 +F5 064F +F6 0650 +F7 00F7 +F8 0651 +F9 00F9 +FA 0652 +FB 00FB +FC 00FC +FD 200E +FE 200F +FF 06D2 diff --git a/data/cp1257 b/data/cp1257 new file mode 100644 index 0000000000..6c3bd7ceac --- /dev/null +++ b/data/cp1257 @@ -0,0 +1,247 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1257 (WinBaltic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8B 2039 +8D 00A8 +8E 02C7 +8F 00B8 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9B 203A +9D 00AF +9E 02DB +A0 00A0 +A2 00A2 +A3 00A3 +A4 00A4 +A6 00A6 +A7 00A7 +A8 00D8 +A9 00A9 +AA 0156 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00C6 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00F8 +B9 00B9 +BA 0157 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00E6 +C0 0104 +C1 012E +C2 0100 +C3 0106 +C4 00C4 +C5 00C5 +C6 0118 +C7 0112 +C8 010C +C9 00C9 +CA 0179 +CB 0116 +CC 0122 +CD 0136 +CE 012A +CF 013B +D0 0160 +D1 0143 +D2 0145 +D3 00D3 +D4 014C +D5 00D5 +D6 00D6 +D7 00D7 +D8 0172 +D9 0141 +DA 015A +DB 016A +DC 00DC +DD 017B +DE 017D +DF 00DF +E0 0105 +E1 012F +E2 0101 +E3 0107 +E4 00E4 +E5 00E5 +E6 0119 +E7 0113 +E8 010D +E9 00E9 +EA 017A +EB 0117 +EC 0123 +ED 0137 +EE 012B +EF 013C +F0 0161 +F1 0144 +F2 0146 +F3 00F3 +F4 014D +F5 00F5 +F6 00F6 +F7 00F7 +F8 0173 +F9 0142 +FA 015B +FB 016B +FC 00FC +FD 017C +FE 017E +FF 02D9 diff --git a/data/cp1258 b/data/cp1258 new file mode 100644 index 0000000000..bf7752b7e8 --- /dev/null +++ b/data/cp1258 @@ -0,0 +1,250 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 1258 (WinVietnamese) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 0102 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 0300 +CD 00CD +CE 00CE +CF 00CF +D0 0110 +D1 00D1 +D2 0309 +D3 00D3 +D4 00D4 +D5 01A0 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 01AF +DE 0303 +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 0103 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 0301 +ED 00ED +EE 00EE +EF 00EF +F0 0111 +F1 00F1 +F2 0323 +F3 00F3 +F4 00F4 +F5 01A1 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 01B0 +FE 20AB +FF 00FF diff --git a/data/cp874 b/data/cp874 new file mode 100644 index 0000000000..d12407c177 --- /dev/null +++ b/data/cp874 @@ -0,0 +1,228 @@ +charset 8bit + +# +# This file defines the font and character mappings used for Windows +# Code Page 874 (Thai) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +7F 007F +80 20AC +85 2026 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +A0 00A0 +A1 0E01 +A2 0E02 +A3 0E03 +A4 0E04 +A5 0E05 +A6 0E06 +A7 0E07 +A8 0E08 +A9 0E09 +AA 0E0A +AB 0E0B +AC 0E0C +AD 0E0D +AE 0E0E +AF 0E0F +B0 0E10 +B1 0E11 +B2 0E12 +B3 0E13 +B4 0E14 +B5 0E15 +B6 0E16 +B7 0E17 +B8 0E18 +B9 0E19 +BA 0E1A +BB 0E1B +BC 0E1C +BD 0E1D +BE 0E1E +BF 0E1F +C0 0E20 +C1 0E21 +C2 0E22 +C3 0E23 +C4 0E24 +C5 0E25 +C6 0E26 +C7 0E27 +C8 0E28 +C9 0E29 +CA 0E2A +CB 0E2B +CC 0E2C +CD 0E2D +CE 0E2E +CF 0E2F +D0 0E30 +D1 0E31 +D2 0E32 +D3 0E33 +D4 0E34 +D5 0E35 +D6 0E36 +D7 0E37 +D8 0E38 +D9 0E39 +DA 0E3A +DF 0E3F +E0 0E40 +E1 0E41 +E2 0E42 +E3 0E43 +E4 0E44 +E5 0E45 +E6 0E46 +E7 0E47 +E8 0E48 +E9 0E49 +EA 0E4A +EB 0E4B +EC 0E4C +ED 0E4D +EE 0E4E +EF 0E4F +F0 0E50 +F1 0E51 +F2 0E52 +F3 0E53 +F4 0E54 +F5 0E55 +F6 0E56 +F7 0E57 +F8 0E58 +F9 0E59 +FA 0E5A +FB 0E5B diff --git a/data/iso-8859-1 b/data/iso-8859-1 new file mode 100644 index 0000000000..86b8c90886 --- /dev/null +++ b/data/iso-8859-1 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-1 +# (Latin1/West European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 00D0 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FE +FF 00FF diff --git a/data/iso-8859-10 b/data/iso-8859-10 new file mode 100644 index 0000000000..7e1399a6dd --- /dev/null +++ b/data/iso-8859-10 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-10 +# (Latin6/Nordic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0104 +A2 0112 +A3 0122 +A4 012A +A5 0128 +A6 0136 +A7 00A7 +A8 013B +A9 0110 +AA 0160 +AB 0166 +AC 017D +AD 00AD +AE 016A +AF 014A +B0 00B0 +B1 0105 +B2 0113 +B3 0123 +B4 012B +B5 0129 +B6 0137 +B7 00B7 +B8 013C +B9 0111 +BA 0161 +BB 0167 +BC 017E +BD 2015 +BE 016B +BF 014B +C0 0100 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 012E +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 0116 +CD 00CD +CE 00CE +CF 00CF +D0 0110 +D1 0145 +D2 014C +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 0168 +D8 00D8 +D9 0172 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 0101 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 012F +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 0117 +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 0146 +F2 014D +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 0169 +F8 00F8 +F9 0173 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FD +FF 0138 diff --git a/data/iso-8859-13 b/data/iso-8859-13 new file mode 100644 index 0000000000..e3b67c693e --- /dev/null +++ b/data/iso-8859-13 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-13 +# (Latin7/Baltic Rim) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 201D +A2 00A2 +A3 00A3 +A4 00A4 +A5 201E +A6 00A6 +A7 00A7 +A8 00D8 +A9 00A9 +AA 0156 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00C6 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 201C +B5 00B5 +B6 00B6 +B7 00B7 +B8 00F8 +B9 00B9 +BA 0157 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00E6 +C0 0104 +C1 012E +C2 0100 +C3 0106 +C4 00C4 +C5 00C5 +C6 0118 +C7 0112 +C8 010C +C9 00C9 +CA 0179 +CB 0116 +CC 0122 +CD 0136 +CE 012A +CF 013B +D0 0160 +D1 0143 +D2 0145 +D3 00D3 +D4 014C +D5 00D5 +D6 00D6 +D7 00D7 +D8 0172 +D9 0141 +DA 015A +DB 016A +DC 00DC +DD 017B +DE 017D +DF 00DF +E0 0105 +E1 012F +E2 0101 +E3 0107 +E4 00E4 +E5 00E5 +E6 0119 +E7 0113 +E8 010D +E9 00E9 +EA 017A +EB 0117 +EC 0123 +ED 0137 +EE 012B +EF 013C +F0 0161 +F1 0144 +F2 0146 +F3 00F3 +F4 014D +F5 00F5 +F6 00F6 +F7 00F7 +F8 0173 +F9 0142 +FA 015B +FB 016B +FC 00FC +FD 017C +FE 017E +FF 2019 diff --git a/data/iso-8859-14 b/data/iso-8859-14 new file mode 100644 index 0000000000..293024b8b8 --- /dev/null +++ b/data/iso-8859-14 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-14 +# (Latin8/Celtic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 1E02 +A2 1E03 +A3 00A3 +A4 010A +A5 010B +A6 1E0A +A7 00A7 +A8 1E80 +A9 00A9 +AA 1E82 +AB 1E0B +AC 1EF2 +AD 00AD +AE 00AE +AF 0178 +B0 1E1E +B1 1E1F +B2 0120 +B3 0121 +B4 1E40 +B5 1E41 +B6 00B6 +B7 1E56 +B8 1E81 +B9 1E57 +BA 1E83 +BB 1E60 +BC 1EF3 +BD 1E84 +BE 1E85 +BF 1E61 +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 0174 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 1E6A +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 0176 +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 0175 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 1E6B +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 0177 +FF 00FF diff --git a/data/iso-8859-15 b/data/iso-8859-15 new file mode 100644 index 0000000000..b306a0c7a9 --- /dev/null +++ b/data/iso-8859-15 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-15 +# (Latin9/West Europe + Euro) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 20AC +A5 00A5 +A6 0160 +A7 00A7 +A8 0161 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 017D +B5 00B5 +B6 00B6 +B7 00B7 +B8 017E +B9 00B9 +BA 00BA +BB 00BB +BC 0152 +BD 0153 +BE 0178 +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 00D0 +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 00DD +DE 00DE +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 00F0 +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 00FD +FE 00FE +FF 00FF diff --git a/data/iso-8859-2 b/data/iso-8859-2 new file mode 100644 index 0000000000..bad8840bb0 --- /dev/null +++ b/data/iso-8859-2 @@ -0,0 +1,253 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-2 +# (Latin2/East European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +84 201E +85 2026 +86 2020 +87 2021 +89 2030 +8A 0160 +8B 2039 +8C 015A +8D 0164 +8E 017D +8F 0179 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +99 2122 +9A 0161 +9B 203A +8C 015B +8D 0165 +8E 017E +8F 017A +A0 00A0 +A1 0104 +A2 02D8 +A3 0141 +A4 00A4 +A5 013D +A6 015A +A7 00A7 +A8 00A8 +A9 0160 +AA 015E +AB 0164 +AC 0179 +AD 00AD +AE 017D +AF 017B +B0 00B0 +B1 0105 +B2 02DB +B3 0142 +B4 00B4 +B5 013E +B6 015B +B7 02C7 +B8 00B8 +B9 0161 +BA 015F +BB 0165 +BC 017A +BD 02DD +BE 017E +BF 017C +C0 0154 +C1 00C1 +C2 00C2 +C3 0102 +C4 00C4 +C5 0139 +C6 0106 +C7 00C7 +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 011A +CD 00CD +CE 00CE +CF 010E +D0 0110 +D1 0143 +D2 0147 +D3 00D3 +D4 00D4 +D5 0150 +D6 00D6 +D7 00D7 +D8 0158 +D9 016E +DA 00DA +DB 0170 +DC 00DC +DD 00DD +DE 0162 +DF 00DF +E0 0155 +E1 00E1 +E2 00E2 +E3 0103 +E4 00E4 +E5 013A +E6 0107 +E7 00E7 +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 011B +ED 00ED +EE 00EE +EF 010F +F0 0111 +F1 0144 +F2 0148 +F3 00F3 +F4 00F4 +F5 0151 +F6 00F6 +F7 00F7 +F8 0159 +F9 016F +FA 00FA +FB 0171 +FC 00FC +FD 00FD +FE 0163 +FF 02D9 diff --git a/data/iso-8859-3 b/data/iso-8859-3 new file mode 100644 index 0000000000..306152b840 --- /dev/null +++ b/data/iso-8859-3 @@ -0,0 +1,244 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-3 +# (Latin3/South European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0126 +A2 02D8 +A3 00A3 +A4 00A4 +A6 0124 +A7 00A7 +A8 00A8 +A9 0130 +AA 015E +AB 011E +AC 0134 +AD 00AD +AF 017B +B0 00B0 +B1 0127 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 0125 +B7 00B7 +B8 00B8 +B9 0131 +BA 015F +BB 011F +BC 0135 +BD 00BD +BF 017C +C0 00C0 +C1 00C1 +C2 00C2 +C4 00C4 +C5 010A +C6 0108 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 0120 +D6 00D6 +D7 00D7 +D8 011C +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 016C +DE 015C +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E4 00E4 +E5 010B +E6 0109 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 0121 +F6 00F6 +F7 00F7 +F8 011D +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 016D +FE 015D +FF 02D9 diff --git a/data/iso-8859-4 b/data/iso-8859-4 new file mode 100644 index 0000000000..1af6ae62d5 --- /dev/null +++ b/data/iso-8859-4 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-4 +# (Latin4/North European) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0104 +A2 0138 +A3 0156 +A4 00A4 +A5 0128 +A6 013B +A7 00A7 +A8 00A8 +A9 0160 +AA 0112 +AB 0122 +AC 0166 +AD 00AD +AE 017D +AF 00AF +B0 00B0 +B1 0105 +B2 02DB +B3 0157 +B4 00B4 +B5 0129 +B6 013C +B7 02C7 +B8 00B8 +B9 0161 +BA 0113 +BB 0123 +BC 0167 +BD 014A +BE 017E +BF 014B +C0 0100 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 012E +C8 010C +C9 00C9 +CA 0118 +CB 00CB +CC 0116 +CD 00CD +CE 00CE +CF 012A +D0 0110 +D1 0145 +D2 014C +D3 0136 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 0172 +DA 00DA +DB 00DB +DC 00DC +DD 0168 +DE 016A +DF 00DF +E0 0101 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 012F +E8 010D +E9 00E9 +EA 0119 +EB 00EB +EC 0117 +ED 00ED +EE 00EE +EF 012B +F0 0111 +F1 0146 +F2 014D +F3 0137 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 0173 +FA 00FA +FB 00FB +FC 00FC +FD 0169 +FE 016B +FF 02D9 diff --git a/data/iso-8859-5 b/data/iso-8859-5 new file mode 100644 index 0000000000..2ca78cfead --- /dev/null +++ b/data/iso-8859-5 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-5 +# (Cyrillic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 0401 +A2 0402 +A3 0403 +A4 0404 +A5 0405 +A6 0406 +A7 0407 +A8 0408 +A9 0409 +AA 040A +AB 040B +AC 040C +AD 00AD +AE 040E +AF 040F +B0 0410 +B1 0411 +B2 0412 +B3 0413 +B4 0414 +B5 0415 +B6 0416 +B7 0417 +B8 0418 +B9 0419 +BA 041A +BB 041B +BC 041C +BD 041D +BE 041E +BF 041F +C0 0420 +C1 0421 +C2 0422 +C3 0423 +C4 0424 +C5 0425 +C6 0426 +C7 0427 +C8 0428 +C9 0429 +CA 042A +CB 042B +CC 042C +CD 042D +CE 042E +CF 042F +D0 0430 +D1 0431 +D2 0432 +D3 0433 +D4 0434 +D5 0435 +D6 0436 +D7 0437 +D8 0438 +D9 0439 +DA 043A +DB 043B +DC 043C +DD 043D +DE 043E +DF 043F +E0 0440 +E1 0441 +E2 0442 +E3 0443 +E4 0444 +E5 0445 +E6 0446 +E7 0447 +E8 0448 +E9 0449 +EA 044A +EB 044B +EC 044C +ED 044D +EE 044E +EF 044F +F0 2116 +F1 0451 +F2 0452 +F3 0453 +F4 0454 +F5 0455 +F6 0456 +F7 0457 +F8 0458 +F9 0459 +FA 045A +FB 045B +FC 045C +FD 00A7 +FE 045E +FF 045F diff --git a/data/iso-8859-6 b/data/iso-8859-6 new file mode 100644 index 0000000000..fd8d7c7bfa --- /dev/null +++ b/data/iso-8859-6 @@ -0,0 +1,206 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-6 +# (Arabic) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +rtol single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0660 +31 0661 +32 0662 +33 0663 +34 0664 +35 0665 +36 0666 +37 0667 +38 0668 +39 0669 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A4 00A4 +AC 060C +AD 00AD +BB 061B +BF 061F +C1 0621 +C2 0622 +C3 0623 +C4 0624 +C5 0625 +C6 0626 +C7 0627 +C8 0628 +C9 0629 +CA 062A +CB 062B +CC 062C +CD 062D +CE 062E +CF 062F +D0 0630 +D1 0631 +D2 0632 +D3 0633 +D4 0634 +D5 0635 +D6 0636 +D7 0637 +D8 0638 +D9 0639 +DA 063A +E0 0640 +E1 0641 +E2 0642 +E3 0643 +E4 0644 +E5 0645 +E6 0646 +E7 0647 +E8 0648 +E9 0649 +EA 064A +EB 064B +EC 064C +ED 064D +EE 064E +EF 064F +F0 0650 +F1 0651 +F2 0652 diff --git a/data/iso-8859-7 b/data/iso-8859-7 new file mode 100644 index 0000000000..b121ccd4c2 --- /dev/null +++ b/data/iso-8859-7 @@ -0,0 +1,245 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-7 +# (Greek) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 02BD +A2 02BC +A3 00A3 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AB 00AB +AC 00AC +AD 00AD +AF 2015 +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 0384 +B5 0385 +B6 0386 +B7 00B7 +B8 0388 +B9 0389 +BA 038A +BB 00BB +BC 038C +BD 00BD +BE 038E +BF 038F +C0 0390 +C1 0391 +C2 0392 +C3 0393 +C4 0394 +C5 0395 +C6 0396 +C7 0397 +C8 0398 +C9 0399 +CA 039A +CB 039B +CC 039C +CD 039D +CE 039E +CF 039F +D0 03A0 +D1 03A1 +D3 03A3 +D4 03A4 +D5 03A5 +D6 03A6 +D7 03A7 +D8 03A8 +D9 03A9 +DA 03AA +DB 03AB +DC 03AC +DD 03AD +DE 03AE +DF 03AF +E0 03B0 +E1 03B1 +E2 03B2 +E3 03B3 +E4 03B4 +E5 03B5 +E6 03B6 +E7 03B7 +E8 03B8 +E9 03B9 +EA 03BA +EB 03BB +EC 03BC +ED 03BD +EE 03BE +EF 03BF +F0 03C0 +F1 03C1 +F2 03C2 +F3 03C3 +F4 03C4 +F5 03C5 +F6 03C6 +F7 03C7 +F8 03C8 +F9 03C9 +FA 03CA +FB 03CB +FC 03CC +FD 03CD +FE 03CE diff --git a/data/iso-8859-8 b/data/iso-8859-8 new file mode 100644 index 0000000000..6d3a7c8c3e --- /dev/null +++ b/data/iso-8859-8 @@ -0,0 +1,213 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-8 +# (Hebrew) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +rtol single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00D7 +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 203E +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00F7 +BB 00BB +BC 00BC +BD 00BD +BE 00BE +DF 2017 +E0 05D0 +E1 05D1 +E2 05D2 +E3 05D3 +E4 05D4 +E5 05D5 +E6 05D6 +E7 05D7 +E8 05D8 +E9 05D9 +EA 05DA +EB 05DB +EC 05DC +ED 05DD +EE 05DE +EF 05DF +F0 05E0 +F1 05E1 +F2 05E2 +F3 05E3 +F4 05E4 +F5 05E5 +F6 05E6 +F7 05E7 +F8 05E8 +F9 05E9 +FA 05EA diff --git a/data/iso-8859-9 b/data/iso-8859-9 new file mode 100644 index 0000000000..2ccfa65e12 --- /dev/null +++ b/data/iso-8859-9 @@ -0,0 +1,251 @@ +charset 8bit + +# +# This file defines the font and character mappings used for ISO-8859-9 +# (Latin5/Turkish) text printing. +# +# The first line consists of: +# +# direction width normal bold italic bold-italic +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +ltor single Courier Courier-Bold Courier-Italic Courier-BoldItalic + +# +# The following lines define the mapping from the 8-bit character set to +# the Unicode glyphs for each character: +# +# char glyph +# +# "Char" and "glyph" are hexadecimal values. +# + +20 0020 +21 0021 +22 0022 +23 0023 +24 0024 +25 0025 +26 0026 +27 0027 +28 0028 +29 0029 +2A 002A +2B 002B +2C 002C +2D 002D +2E 002E +2F 002F +30 0030 +31 0031 +32 0032 +33 0033 +34 0034 +35 0035 +36 0036 +37 0037 +38 0038 +39 0039 +3A 003A +3B 003B +3C 003C +3D 003D +3E 003E +3F 003F +40 0040 +41 0041 +42 0042 +43 0043 +44 0044 +45 0045 +46 0046 +47 0047 +48 0048 +49 0049 +4A 004A +4B 004B +4C 004C +4D 004D +4E 004E +4F 004F +50 0050 +51 0051 +52 0052 +53 0053 +54 0054 +55 0055 +56 0056 +57 0057 +58 0058 +59 0059 +5A 005A +5B 005B +5C 005C +5D 005D +5E 005E +5F 005F +60 0060 +61 0061 +62 0062 +63 0063 +64 0064 +65 0065 +66 0066 +67 0067 +68 0068 +69 0069 +6A 006A +6B 006B +6C 006C +6D 006D +6E 006E +6F 006F +70 0070 +71 0071 +72 0072 +73 0073 +74 0074 +75 0075 +76 0076 +77 0077 +78 0078 +79 0079 +7A 007A +7B 007B +7C 007C +7D 007D +7E 007E +80 20AC +82 201A +83 0192 +84 201E +85 2026 +86 2020 +87 2021 +88 02C6 +89 2030 +8A 0160 +8B 2039 +8C 0152 +91 2018 +92 2019 +93 201C +94 201D +95 2022 +96 2013 +97 2014 +98 02DC +99 2122 +9A 0161 +9B 203A +9C 0153 +9F 0178 +A0 00A0 +A1 00A1 +A2 00A2 +A3 00A3 +A4 00A4 +A5 00A5 +A6 00A6 +A7 00A7 +A8 00A8 +A9 00A9 +AA 00AA +AB 00AB +AC 00AC +AD 00AD +AE 00AE +AF 00AF +B0 00B0 +B1 00B1 +B2 00B2 +B3 00B3 +B4 00B4 +B5 00B5 +B6 00B6 +B7 00B7 +B8 00B8 +B9 00B9 +BA 00BA +BB 00BB +BC 00BC +BD 00BD +BE 00BE +BF 00BF +C0 00C0 +C1 00C1 +C2 00C2 +C3 00C3 +C4 00C4 +C5 00C5 +C6 00C6 +C7 00C7 +C8 00C8 +C9 00C9 +CA 00CA +CB 00CB +CC 00CC +CD 00CD +CE 00CE +CF 00CF +D0 011E +D1 00D1 +D2 00D2 +D3 00D3 +D4 00D4 +D5 00D5 +D6 00D6 +D7 00D7 +D8 00D8 +D9 00D9 +DA 00DA +DB 00DB +DC 00DC +DD 0130 +DE 015E +DF 00DF +E0 00E0 +E1 00E1 +E2 00E2 +E3 00E3 +E4 00E4 +E5 00E5 +E6 00E6 +E7 00E7 +E8 00E8 +E9 00E9 +EA 00EA +EB 00EB +EC 00EC +ED 00ED +EE 00EE +EF 00EF +F0 011F +F1 00F1 +F2 00F2 +F3 00F3 +F4 00F4 +F5 00F5 +F6 00F6 +F7 00F7 +F8 00F8 +F9 00F9 +FA 00FA +FB 00FB +FC 00FC +FD 0131 +FE 015F +FF 00FF diff --git a/data/psglyphs b/data/psglyphs new file mode 100644 index 0000000000..c4a902c66c --- /dev/null +++ b/data/psglyphs @@ -0,0 +1,1051 @@ +0020 space +0021 exclam +0022 quotedbl +0023 numbersign +0024 dollar +0025 percent +0026 ampersand +0027 quotesingle +0028 parenleft +0029 parenright +002a asterisk +002b plus +002c comma +002d minus +002e period +002f slash +0030 zero +0031 one +0032 two +0033 three +0034 four +0035 five +0036 six +0037 seven +0038 eight +0039 nine +003a colon +003b semicolon +003c less +003d equal +003e greater +003f question +0040 at +0041 A +0042 B +0043 C +0044 D +0045 E +0046 F +0047 G +0048 H +0049 I +004a J +004b K +004c L +004d M +004e N +004f O +0050 P +0051 Q +0052 R +0053 S +0054 T +0055 U +0056 V +0057 W +0058 X +0059 Y +005a Z +005b bracketleft +005c backslash +005d bracketright +005e asciicircum +005f underscore +0060 grave +0061 a +0062 b +0063 c +0064 d +0065 e +0066 f +0067 g +0068 h +0069 i +006a j +006b k +006c l +006d m +006e n +006f o +0070 p +0071 q +0072 r +0073 s +0074 t +0075 u +0076 v +0077 w +0078 x +0079 y +007a z +007b braceleft +007c bar +007d braceright +007e asciitilde +00a0 space +00a1 exclamdown +00a2 cent +00a3 sterling +00a4 currency +00a5 yen +00a6 brokenbar +00a7 section +00a8 dieresis +00a9 copyright +00aa ordfeminine +00ab guillemotleft +00ac logicalnot +00ad hyphen +00ae registered +00af macron +00b0 degree +00b1 plusminus +00b2 twosuperior +00b3 threesuperior +00b4 acute +00b5 mu +00b6 paragraph +00b7 periodcentered +00b8 cedilla +00b9 onesuperior +00ba ordmasculine +00bb guillemotright +00bc onequarter +00bd onehalf +00be threequarters +00bf questiondown +00c0 Agrave +00c1 Aacute +00c2 Acircumflex +00c3 Atilde +00c4 Adieresis +00c5 Aring +00c6 AE +00c7 Ccedilla +00c8 Egrave +00c9 Eacute +00ca Ecircumflex +00cb Edieresis +00cc Igrave +00cd Iacute +00ce Icircumflex +00cf Idieresis +00d0 Eth +00d1 Ntilde +00d2 Ograve +00d3 Oacute +00d4 Ocircumflex +00d5 Otilde +00d6 Odieresis +00d7 multiply +00d8 Oslash +00d9 Ugrave +00da Uacute +00db Ucircumflex +00dc Udieresis +00dd Yacute +00de Thorn +00df germandbls +00e0 agrave +00e1 aacute +00e2 acircumflex +00e3 atilde +00e4 adieresis +00e5 aring +00e6 ae +00e7 ccedilla +00e8 egrave +00e9 eacute +00ea ecircumflex +00eb edieresis +00ec igrave +00ed iacute +00ee icircumflex +00ef idieresis +00f0 eth +00f1 ntilde +00f2 ograve +00f3 oacute +00f4 ocircumflex +00f5 otilde +00f6 odieresis +00f7 divide +00f8 oslash +00f9 ugrave +00fa uacute +00fb ucircumflex +00fc udieresis +00fd yacute +00fe thorn +00ff ydieresis +0100 Amacron +0101 amacron +0102 Abreve +0103 abreve +0104 Aogonek +0105 aogonek +0106 Cacute +0107 cacute +0108 Ccircumflex +0109 ccircumflex +010a Cdotaccent +010b cdotaccent +010c Ccaron +010d ccaron +010e Dcaron +010f dcaron +0110 Dcroat +0111 dcroat +0112 Emacron +0113 emacron +0114 Ebreve +0115 ebreve +0116 Edotaccent +0117 edotaccent +0118 Eogonek +0119 eogonek +011a Ecaron +011b ecaron +011c Gcircumflex +011d gcircumflex +011e Gbreve +011f gbreve +0120 Gdotaccent +0121 gdotaccent +0122 Gcommaaccent +0123 gcommaaccent +0124 Hcircumflex +0125 hcircumflex +0126 Hbar +0127 hbar +0128 Itilde +0129 itilde +012a Imacron +012b imacron +012c Ibreve +012d ibreve +012e Iogonek +012f iogonek +0130 Idotaccent +0131 dotlessi +0132 IJ +0133 ij +0134 Jcircumflex +0135 jcircumflex +0136 Kcommaaccent +0137 kcommaaccent +0138 kgreenlandic +0139 Lacute +013a lacute +013b Lcommaaccent +013c lcommaaccent +013d Lcaron +013e lcaron +013f Ldot +0140 ldot +0141 Lslash +0142 lslash +0143 Nacute +0144 nacute +0145 Ncommaaccent +0146 ncommaaccent +0147 Ncaron +0148 ncaron +0149 napostrophe +014a Eng +014b eng +014c Omacron +014d omacron +014e Obreve +014f obreve +0150 Ohungarumlaut +0151 ohungarumlaut +0152 OE +0153 oe +0154 Racute +0155 racute +0156 Rcommaaccent +0157 rcommaaccent +0158 Rcaron +0159 rcaron +015a Sacute +015b sacute +015c Scircumflex +015d scircumflex +015e Scedilla +015f scedilla +0160 Scaron +0161 scaron +0162 Tcommaaccent +0163 tcommaaccent +0164 Tcaron +0165 tcaron +0166 Tbar +0167 tbar +0168 Utilde +0169 utilde +016a Umacron +016b umacron +016c Ubreve +016d ubreve +016e Uring +016f uring +0170 Uhungarumlaut +0171 uhungarumlaut +0172 Uogonek +0173 uogonek +0174 Wcircumflex +0175 wcircumflex +0176 Ycircumflex +0177 ycircumflex +0178 Ydieresis +0179 Zacute +017a zacute +017b Zdotaccent +017c zdotaccent +017d Zcaron +017e zcaron +017f longs +0192 florin +01a0 Ohorn +01a1 ohorn +01af Uhorn +01b0 uhorn +01e6 Gcaron +01e7 gcaron +01fa Aringacute +01fb aringacute +01fc AEacute +01fd aeacute +01fe Oslashacute +01ff oslashacute +0218 Scommaaccent +0219 scommaaccent +021a Tcommaaccent +021b tcommaaccent +02bc afii57929 +02bd afii64937 +02c6 circumflex +02c7 caron +02c9 macron +02d8 breve +02d9 dotaccent +02da ring +02db ogonek +02dc tilde +02dd hungarumlaut +0300 gravecomb +0301 acutecomb +0303 tildecomb +0309 hookabovecomb +0323 dotbelowcomb +0384 tonos +0385 dieresistonos +0386 Alphatonos +0387 anoteleia +0388 Epsilontonos +0389 Etatonos +038a Iotatonos +038c Omicrontonos +038e Upsilontonos +038f Omegatonos +0390 iotadieresistonos +0391 Alpha +0392 Beta +0393 Gamma +0394 Delta +0395 Epsilon +0396 Zeta +0397 Eta +0398 Theta +0399 Iota +039a Kappa +039b Lambda +039c Mu +039d Nu +039e Xi +039f Omicron +03a0 Pi +03a1 Rho +03a3 Sigma +03a4 Tau +03a5 Upsilon +03a6 Phi +03a7 Chi +03a8 Psi +03a9 Omega +03aa Iotadieresis +03ab Upsilondieresis +03ac alphatonos +03ad epsilontonos +03ae etatonos +03af iotatonos +03b0 upsilondieresistonos +03b1 alpha +03b2 beta +03b3 gamma +03b4 delta +03b5 epsilon +03b6 zeta +03b7 eta +03b8 theta +03b9 iota +03ba kappa +03bb lambda +03bc mu +03bd nu +03be xi +03bf omicron +03c0 pi +03c1 rho +03c2 sigma1 +03c3 sigma +03c4 tau +03c5 upsilon +03c6 phi +03c7 chi +03c8 psi +03c9 omega +03ca iotadieresis +03cb upsilondieresis +03cc omicrontonos +03cd upsilontonos +03ce omegatonos +03d1 theta1 +03d2 Upsilon1 +03d5 phi1 +03d6 omega1 +0401 afii10023 +0402 afii10051 +0403 afii10052 +0404 afii10053 +0405 afii10054 +0406 afii10055 +0407 afii10056 +0408 afii10057 +0409 afii10058 +040a afii10059 +040b afii10060 +040c afii10061 +040e afii10062 +040f afii10145 +0410 afii10017 +0411 afii10018 +0412 afii10019 +0413 afii10020 +0414 afii10021 +0415 afii10022 +0416 afii10024 +0417 afii10025 +0418 afii10026 +0419 afii10027 +041a afii10028 +041b afii10029 +041c afii10030 +041d afii10031 +041e afii10032 +041f afii10033 +0420 afii10034 +0421 afii10035 +0422 afii10036 +0423 afii10037 +0424 afii10038 +0425 afii10039 +0426 afii10040 +0427 afii10041 +0428 afii10042 +0429 afii10043 +042a afii10044 +042b afii10045 +042c afii10046 +042d afii10047 +042e afii10048 +042f afii10049 +0430 afii10065 +0431 afii10066 +0432 afii10067 +0433 afii10068 +0434 afii10069 +0435 afii10070 +0436 afii10072 +0437 afii10073 +0438 afii10074 +0439 afii10075 +043a afii10076 +043b afii10077 +043c afii10078 +043d afii10079 +043e afii10080 +043f afii10081 +0440 afii10082 +0441 afii10083 +0442 afii10084 +0443 afii10085 +0444 afii10086 +0445 afii10087 +0446 afii10088 +0447 afii10089 +0448 afii10090 +0449 afii10091 +044a afii10092 +044b afii10093 +044c afii10094 +044d afii10095 +044e afii10096 +044f afii10097 +0451 afii10071 +0452 afii10099 +0453 afii10100 +0454 afii10101 +0455 afii10102 +0456 afii10103 +0457 afii10104 +0458 afii10105 +0459 afii10106 +045a afii10107 +045b afii10108 +045c afii10109 +045e afii10110 +045f afii10193 +0462 afii10146 +0463 afii10194 +0472 afii10147 +0473 afii10195 +0474 afii10148 +0475 afii10196 +0490 afii10050 +0491 afii10098 +04d9 afii10846 +05b0 afii57799 +05b1 afii57801 +05b2 afii57800 +05b3 afii57802 +05b4 afii57793 +05b5 afii57794 +05b6 afii57795 +05b7 afii57798 +05b8 afii57797 +05b9 afii57806 +05bb afii57796 +05bc afii57807 +05bd afii57839 +05be afii57645 +05bf afii57841 +05c0 afii57842 +05c1 afii57804 +05c2 afii57803 +05c3 afii57658 +05d0 afii57664 +05d1 afii57665 +05d2 afii57666 +05d3 afii57667 +05d4 afii57668 +05d5 afii57669 +05d6 afii57670 +05d7 afii57671 +05d8 afii57672 +05d9 afii57673 +05da afii57674 +05db afii57675 +05dc afii57676 +05dd afii57677 +05de afii57678 +05df afii57679 +05e0 afii57680 +05e1 afii57681 +05e2 afii57682 +05e3 afii57683 +05e4 afii57684 +05e5 afii57685 +05e6 afii57686 +05e7 afii57687 +05e8 afii57688 +05e9 afii57689 +05ea afii57690 +05f0 afii57716 +05f1 afii57717 +05f2 afii57718 +060c afii57388 +061b afii57403 +061f afii57407 +0621 afii57409 +0622 afii57410 +0623 afii57411 +0624 afii57412 +0625 afii57413 +0626 afii57414 +0627 afii57415 +0628 afii57416 +0629 afii57417 +062a afii57418 +062b afii57419 +062c afii57420 +062d afii57421 +062e afii57422 +062f afii57423 +0630 afii57424 +0631 afii57425 +0632 afii57426 +0633 afii57427 +0634 afii57428 +0635 afii57429 +0636 afii57430 +0637 afii57431 +0638 afii57432 +0639 afii57433 +063a afii57434 +0640 afii57440 +0641 afii57441 +0642 afii57442 +0643 afii57443 +0644 afii57444 +0645 afii57445 +0646 afii57446 +0647 afii57470 +0648 afii57448 +0649 afii57449 +064a afii57450 +064b afii57451 +064c afii57452 +064d afii57453 +064e afii57454 +064f afii57455 +0650 afii57456 +0651 afii57457 +0652 afii57458 +0660 afii57392 +0661 afii57393 +0662 afii57394 +0663 afii57395 +0664 afii57396 +0665 afii57397 +0666 afii57398 +0667 afii57399 +0668 afii57400 +0669 afii57401 +066a afii57381 +066d afii63167 +0679 afii57511 +067e afii57506 +0686 afii57507 +0688 afii57512 +0691 afii57513 +0698 afii57508 +06a4 afii57505 +06af afii57509 +06ba afii57514 +06d2 afii57519 +06d5 afii57534 +1e80 Wgrave +1e81 wgrave +1e82 Wacute +1e83 wacute +1e84 Wdieresis +1e85 wdieresis +1ef2 Ygrave +1ef3 ygrave +200c afii61664 +200d afii301 +200e afii299 +200f afii300 +2012 figuredash +2013 endash +2014 emdash +2015 afii00208 +2017 underscoredbl +2018 quoteleft +2019 quoteright +201a quotesinglbase +201b quotereversed +201c quotedblleft +201d quotedblright +201e quotedblbase +2020 dagger +2021 daggerdbl +2022 bullet +2024 onedotenleader +2025 twodotenleader +2026 ellipsis +202c afii61573 +202d afii61574 +202e afii61575 +2030 perthousand +2032 minute +2033 second +2039 guilsinglleft +203a guilsinglright +203c exclamdbl +2044 fraction +2070 zerosuperior +2074 foursuperior +2075 fivesuperior +2076 sixsuperior +2077 sevensuperior +2078 eightsuperior +2079 ninesuperior +207d parenleftsuperior +207e parenrightsuperior +207f nsuperior +2080 zeroinferior +2081 oneinferior +2082 twoinferior +2083 threeinferior +2084 fourinferior +2085 fiveinferior +2086 sixinferior +2087 seveninferior +2088 eightinferior +2089 nineinferior +208d parenleftinferior +208e parenrightinferior +20a1 colonmonetary +20a3 franc +20a4 lira +20a7 peseta +20aa afii57636 +20ab dong +20ac Euro +2105 afii61248 +2111 Ifraktur +2113 afii61289 +2116 afii61352 +2118 weierstrass +211c Rfraktur +211e prescription +2122 trademark +2126 Omega +212e estimated +2135 aleph +2153 onethird +2154 twothirds +215b oneeighth +215c threeeighths +215d fiveeighths +215e seveneighths +2190 arrowleft +2191 arrowup +2192 arrowright +2193 arrowdown +2194 arrowboth +2195 arrowupdn +21a8 arrowupdnbse +21b5 carriagereturn +21d0 arrowdblleft +21d1 arrowdblup +21d2 arrowdblright +21d3 arrowdbldown +21d4 arrowdblboth +2200 universal +2202 partialdiff +2203 existential +2205 emptyset +2206 Delta +2207 gradient +2208 element +2209 notelement +220b suchthat +220f product +2211 summation +2212 minus +2215 fraction +2217 asteriskmath +2219 periodcentered +221a radical +221d proportional +221e infinity +221f orthogonal +2220 angle +2227 logicaland +2228 logicalor +2229 intersection +222a union +222b integral +2234 therefore +223c similar +2245 congruent +2248 approxequal +2260 notequal +2261 equivalence +2264 lessequal +2265 greaterequal +2282 propersubset +2283 propersuperset +2284 notsubset +2286 reflexsubset +2287 reflexsuperset +2295 circleplus +2297 circlemultiply +22a5 perpendicular +22c5 dotmath +2302 house +2310 revlogicalnot +2320 integraltp +2321 integralbt +2329 angleleft +232a angleright +2500 SF100000 +2502 SF110000 +250c SF010000 +2510 SF030000 +2514 SF020000 +2518 SF040000 +251c SF080000 +2524 SF090000 +252c SF060000 +2534 SF070000 +253c SF050000 +2550 SF430000 +2551 SF240000 +2552 SF510000 +2553 SF520000 +2554 SF390000 +2555 SF220000 +2556 SF210000 +2557 SF250000 +2558 SF500000 +2559 SF490000 +255a SF380000 +255b SF280000 +255c SF270000 +255d SF260000 +255e SF360000 +255f SF370000 +2560 SF420000 +2561 SF190000 +2562 SF200000 +2563 SF230000 +2564 SF470000 +2565 SF480000 +2566 SF410000 +2567 SF450000 +2568 SF460000 +2569 SF400000 +256a SF540000 +256b SF530000 +256c SF440000 +2580 upblock +2584 dnblock +2588 block +258c lfblock +2590 rtblock +2591 ltshade +2592 shade +2593 dkshade +25a0 filledbox +25a1 H22073 +25aa H18543 +25ab H18551 +25ac filledrect +25b2 triagup +25ba triagrt +25bc triagdn +25c4 triaglf +25ca lozenge +25cb circle +25cf H18533 +25d8 invbullet +25d9 invcircle +25e6 openbullet +263a smileface +263b invsmileface +263c sun +2640 female +2642 male +2660 spade +2663 club +2665 heart +2666 diamond +266a musicalnote +266b musicalnotedbl +f6be dotlessj +f6bf LL +f6c0 ll +f6c1 Scedilla +f6c2 scedilla +f6c3 commaaccent +f6c4 afii10063 +f6c5 afii10064 +f6c6 afii10192 +f6c7 afii10831 +f6c8 afii10832 +f6c9 Acute +f6ca Caron +f6cb Dieresis +f6cc DieresisAcute +f6cd DieresisGrave +f6ce Grave +f6cf Hungarumlaut +f6d0 Macron +f6d1 cyrBreve +f6d2 cyrFlex +f6d3 dblGrave +f6d4 cyrbreve +f6d5 cyrflex +f6d6 dblgrave +f6d7 dieresisacute +f6d8 dieresisgrave +f6d9 copyrightserif +f6da registerserif +f6db trademarkserif +f6dc onefitted +f6dd rupiah +f6de threequartersemdash +f6df centinferior +f6e0 centsuperior +f6e1 commainferior +f6e2 commasuperior +f6e3 dollarinferior +f6e4 dollarsuperior +f6e5 hypheninferior +f6e6 hyphensuperior +f6e7 periodinferior +f6e8 periodsuperior +f6e9 asuperior +f6ea bsuperior +f6eb dsuperior +f6ec esuperior +f6ed isuperior +f6ee lsuperior +f6ef msuperior +f6f0 osuperior +f6f1 rsuperior +f6f2 ssuperior +f6f3 tsuperior +f6f4 Brevesmall +f6f5 Caronsmall +f6f6 Circumflexsmall +f6f7 Dotaccentsmall +f6f8 Hungarumlautsmall +f6f9 Lslashsmall +f6fa OEsmall +f6fb Ogoneksmall +f6fc Ringsmall +f6fd Scaronsmall +f6fe Tildesmall +f6ff Zcaronsmall +f721 exclamsmall +f724 dollaroldstyle +f726 ampersandsmall +f730 zerooldstyle +f731 oneoldstyle +f732 twooldstyle +f733 threeoldstyle +f734 fouroldstyle +f735 fiveoldstyle +f736 sixoldstyle +f737 sevenoldstyle +f738 eightoldstyle +f739 nineoldstyle +f73f questionsmall +f760 Gravesmall +f761 Asmall +f762 Bsmall +f763 Csmall +f764 Dsmall +f765 Esmall +f766 Fsmall +f767 Gsmall +f768 Hsmall +f769 Ismall +f76a Jsmall +f76b Ksmall +f76c Lsmall +f76d Msmall +f76e Nsmall +f76f Osmall +f770 Psmall +f771 Qsmall +f772 Rsmall +f773 Ssmall +f774 Tsmall +f775 Usmall +f776 Vsmall +f777 Wsmall +f778 Xsmall +f779 Ysmall +f77a Zsmall +f7a1 exclamdownsmall +f7a2 centoldstyle +f7a8 Dieresissmall +f7af Macronsmall +f7b4 Acutesmall +f7b8 Cedillasmall +f7bf questiondownsmall +f7e0 Agravesmall +f7e1 Aacutesmall +f7e2 Acircumflexsmall +f7e3 Atildesmall +f7e4 Adieresissmall +f7e5 Aringsmall +f7e6 AEsmall +f7e7 Ccedillasmall +f7e8 Egravesmall +f7e9 Eacutesmall +f7ea Ecircumflexsmall +f7eb Edieresissmall +f7ec Igravesmall +f7ed Iacutesmall +f7ee Icircumflexsmall +f7ef Idieresissmall +f7f0 Ethsmall +f7f1 Ntildesmall +f7f2 Ogravesmall +f7f3 Oacutesmall +f7f4 Ocircumflexsmall +f7f5 Otildesmall +f7f6 Odieresissmall +f7f8 Oslashsmall +f7f9 Ugravesmall +f7fa Uacutesmall +f7fb Ucircumflexsmall +f7fc Udieresissmall +f7fd Yacutesmall +f7fe Thornsmall +f7ff Ydieresissmall +f8e5 radicalex +f8e6 arrowvertex +f8e7 arrowhorizex +f8e8 registersans +f8e9 copyrightsans +f8ea trademarksans +f8eb parenlefttp +f8ec parenleftex +f8ed parenleftbt +f8ee bracketlefttp +f8ef bracketleftex +f8f0 bracketleftbt +f8f1 bracelefttp +f8f2 braceleftmid +f8f3 braceleftbt +f8f4 braceex +f8f5 integralex +f8f6 parenrighttp +f8f7 parenrightex +f8f8 parenrightbt +f8f9 bracketrighttp +f8fa bracketrightex +f8fb bracketrightbt +f8fc bracerighttp +f8fd bracerightmid +f8fe bracerightbt +fb00 ff +fb01 fi +fb02 fl +fb03 ffi +fb04 ffl +fb1f afii57705 +fb2a afii57694 +fb2b afii57695 +fb35 afii57723 +fb4b afii57700 diff --git a/data/testprint.ps b/data/testprint.ps new file mode 100644 index 0000000000..9ebcff3b6f --- /dev/null +++ b/data/testprint.ps @@ -0,0 +1,505 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset testprint/1.0 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: May 11, 1999 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset testprint 1.1 0 +% +% PostScript test page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2000 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. +% +/OCTANT { % Draw a color wheel OCTANT... + % (name) radius r g b OCTANT - + % Loop through 100 shades... + 0 0.010101 0.98 { + % Set the color... + 3 index 1 eq % R == 1? + 3 index 1 eq % G == 1? + 3 index 1 eq % B == 1? + and and { + 0 index 4 index mul % R * val + 1 index 4 index mul % G * val + 2 index 4 index mul % B * val + } { + 0 index 4 index mul % R * val + 1 index neg 1 add add % + (1 - val) + 1 index 4 index mul % G * val + 2 index neg 1 add add % + (1 - val) + 2 index 4 index mul % B * val + 3 index neg 1 add add % + (1 - val) + } ifelse + setrgbcolor + + % Draw a polygon... + dup 5 index mul dup 0 % x1, y1 + moveto + 0.707106781 mul dup lineto % x2, y2 + + 0.010101 add 4 index mul dup % x3 + 0.707106781 mul dup lineto % x3, y3 + 0 lineto % x4, y4 + closepath + fill + } for + + % Draw a line around the polygons... + pop pop pop dup + 0 setgray + 0 0 moveto + dup 0 lineto + 0.707106781 mul dup lineto + closepath + stroke + + % Draw the label... + 0 exch dup -9 div exch % text offset = 0, -radius/9 + dup 0.923879532 mul % x = radius * cos(22.5) + exch 0.382683432 mul % y = radius * cos(22.5) + moveto % position label + gsave + 22.5 rotate % rotate label + rmoveto % offset label + show % show label + grestore +} bind def +/CENTER { % Draw centered text + % (name) CENTER - + dup stringwidth pop % Get the width of the string + 0.5 mul neg 0 rmoveto % Shift left 1/2 of the distance + show % Show the string +} bind def +/RIGHT { % Draw right-justified text + % (name) RIGHT - + dup stringwidth pop % Get the width of the string + neg 0 rmoveto % Shift left the entire distance + show % Show the string +} bind def +/NUMBER { % Draw a number + % power n NUMBER - + 1 index 1 eq { % power == 1? + round cvi exch pop % Convert "n" to integer + } { + 1 index mul round exch div % Truncate extra decimal places + } ifelse + 100 string cvs show % Convert to a string and show it... +} bind def +/CUPSLOGO { % Draw the CUPS logo + % height CUPSLOGO + % Start with a big C... + /Helvetica findfont 1 index scalefont setfont + 0 setgray + 0 0 moveto + (C) show + + % Then "UNIX Printing System" much smaller... + /Helvetica-Bold findfont 1 index 9 div scalefont setfont + 0.25 mul + dup dup 2.0 mul moveto + (UNIX) show + dup dup 1.6 mul moveto + (Printing) show + dup 1.2 mul moveto + (System) show +} bind def +/ESPLOGO { % Draw the ESP logo + % height ESPLOGO + % Compute the size of the logo... + 0 0 + 2 index 1.5 mul 3 index + + % Do the "metallic" fill from 10% black to 40% black... + 1 -0.001 0 { + dup % loopval + -0.15 mul % loopval * -0.15 + 0.9 add % 0.9 - loopval * 0.15 + setgray % set gray shade + + 0 % x + 1 index neg % loopval + 1 add % 1 - loopval + 3 index % height + mul % height * (1 - loopval) + moveto % starting point + + dup % loopval + 3 index % width + mul % loopval * width + 2 index % height + lineto % Next point + + 0 % x + 2 index % height + lineto % Next point + + closepath + fill + + dup % loopval + 0.15 mul % loopval * 0.15 + 0.6 add % 0.6 + loopval * 0.15 + setgray + + dup % loopval + neg 1 add % 1 - loopval + 3 index % width + mul % (1 - loopval) * width + 0 % y + moveto % Starting point + + 2 index % width + exch % loopval + 2 index % height + mul % loopval * height + lineto % Next point + + 1 index % width + 0 % y + lineto % Next point + + closepath + fill + } for + + 0 setgray rectstroke + + /Helvetica-BoldOblique findfont 1 index 3 div scalefont setfont + dup 40 div + + dup 4 mul 1 index 25 mul moveto (E) show + dup 10 mul 1 index 15 mul moveto (S) show + dup 16 mul 1 index 5 mul moveto (P) show + + /Helvetica-BoldOblique findfont 2 index 5 div scalefont setfont + dup 14 mul 1 index 29 mul moveto (asy) show + dup 20 mul 1 index 19 mul moveto (oftware) show + dup 26 mul 1 index 9 mul moveto (roducts) show + + pop +} bind def +%%EndResource +%%EndProlog +%%Page: 1 1 +gsave + + % Determine the imageable area and device resolution... + initclip newpath clippath pathbbox % Get bounding rectangle + 72 div /pageTop exch def % Get top margin in inches + 72 div /pageRight exch def % Get right margin in inches + 72 div /pageBottom exch def % Get bottom margin in inches + 72 div /pageLeft exch def % Get left margin in inches + + 4 setlinewidth % Draw wide lines + 0 setgray closepath stroke % Draw a clipping rectangle + 1 setlinewidth % Draw normal lines + + /pageWidth pageRight pageLeft sub def % pageWidth = pageRight - pageLeft + /pageHeight pageTop pageBottom sub def% pageHeight = pageTop - pageBottom + + 72 72 dtransform % Get device resolution per inch + /yResolution exch abs def % yResolution = abs(yres) + /xResolution exch abs def % xResolution = abs(xres) + + % Create fonts... + /bigFont /Helvetica-Bold findfont % bigFont = Helvetica-Bold + pageWidth 4 mul scalefont def % size = pageWidth * 4 (nominally 34) + + /mediumFont /Helvetica findfont % mediumFont = Helvetica + pageWidth 2 mul scalefont def % size = pageWidth * 2 (nominally 17) + + /smallFont /Times-Roman findfont % smallFont = Times-Roman + pageWidth 1.5 mul scalefont def % size = pageWidth * 1.5 (nominally 13) + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Draw the color wheel... + mediumFont setfont % Font + 0 setgray % Color + + gsave + % Position the wheel on the left side... + pageWidth 18 mul % x = pageWidth * 1/4 * 72 + pageHeight 54 mul % y = pageHeight * 3/4 * 72 + translate + + % Size the wheel... + pageWidth 9 mul % radius = pageWidth * 1/8 * 72 + + % Draw the colors... + dup (C) exch 0 1 1 OCTANT 45 rotate + dup (M) exch 1 0 1 OCTANT 45 rotate + dup (Y) exch 1 1 0 OCTANT 45 rotate + dup (K) exch 0 0 0 OCTANT 45 rotate + dup (R) exch 1 0 0 OCTANT 45 rotate + dup (G) exch 0 1 0 OCTANT 45 rotate + dup (B) exch 0 0 1 OCTANT 45 rotate + (W) exch 1 1 1 OCTANT 45 rotate + grestore + + % Label the color wheel... + pageWidth 18 mul % x = pageWidth * 1/4 * 72 + pageHeight 44 mul % y = pageHeight * 19/32 * 72 + moveto % Position the text + (Color Wheel) CENTER % Show the text centered + + % Draw radial lines... + gsave + 0 setlinewidth % 1 pixel lines + + % Position the lines on the left side... + pageWidth 54 mul % x = pageWidth * 3/4 * 72 + pageHeight 54 mul % y = pageHeight * 3/4 * 72 + translate + + % Size the wheel... + pageWidth 9 mul % radius = pageWidth * 1/8 * 72 + + % Loop at 1 degree increments + 0 1 359 { + pop % Discard angle - not used + 0 0 moveto % Start line at the center + dup 0 lineto % Draw to the radius + 1 rotate % Rotate 1 degree + } for + + pop % Discard radius - not needed anymore + stroke % Draw lines... + + grestore + + % Label the lines... + pageWidth 54 mul % x = pageWidth * 3/4 * 72 + pageHeight 44 mul % y = pageHeight * 19/32 * 72 + moveto % Position the text + (1 Degree Radial Lines) CENTER % Show the text centered + + % Imageable area... + pageWidth 19.5 mul % Height of imageable area + + pageWidth 4.5 mul % x = pageWidth * 1/16 * 72 + pageHeight 35.5 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 1/4 * 72 + 3 index % height + 0.5 setgray rectfill % Draw a shadow + + pageWidth 4 mul % x = pageWidth * 1/16 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 3/8 * 72 + 3 index % height + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + pop % Discard height + + % Label the imageable area... + pageWidth 4 mul % x = pageWidth * 1/16 * 72 + pageHeight 37 mul % y = pageHeight * 1/2 * 72 + moveto % Position the text + mediumFont setfont % Font + (Imageable Area) show % Show the text + + smallFont setfont % Font + pageWidth 14 mul % x = pageWidth * 3/16 * 72 + pageHeight 36 mul % y = pageWidth * 1/2 * 72 + pageWidth -3 mul add % y -= 2 * smallFont height + + % Page Size inches + 2 copy moveto % Move to x & y + (Page Size: ) RIGHT % Label + 100 pageWidth NUMBER % pageWidth + (x) show % "x" + 100 pageHeight NUMBER % pageHeight + (in) show % "in" + + % Page Size millimeters + pageWidth -1.5 mul add % Move down... + + 2 copy moveto % Move to x & y + 10 pageWidth 25.4 mul NUMBER % pageWidth + (x) show % "x" + 10 pageHeight 25.4 mul NUMBER % pageHeight + (mm) show % "mm" + + % Lower-left inches + pageWidth -3 mul add % Move down... + + 2 copy moveto % Move to x & y + (Lower-Left: ) RIGHT % Label + 100 pageLeft NUMBER % pageLeft + (x) show % "x" + 100 pageBottom NUMBER % pageBottom + (in) show % "in" + + % Lower-left millimeters + pageWidth -1.5 mul add % Move down... + + 2 copy moveto % Move to x & y + 10 pageLeft 25.4 mul NUMBER % pageLeft + (x) show % "x" + 10 pageBottom 25.4 mul NUMBER % pageBottom + (mm) show % "mm" + + % Upper-right inches + pageWidth -3 mul add % Move down... + + 2 copy moveto % Move to x & y + (Upper-Right: ) RIGHT % Label + 100 pageRight NUMBER % pageRight + (x) show % "x" + 100 pageTop NUMBER % pageTop + (in) show % "in" + + % Upper-right millimeters + pageWidth -1.5 mul add % Move down... + + 2 copy moveto % Move to x & y + 10 pageRight 25.4 mul NUMBER % pageRight + (x) show % "x" + 10 pageTop 25.4 mul NUMBER % pageTop + (mm) show % "mm" + + % Resolution dots-per-inch + pageWidth -3 mul add % Move down... + + 2 copy moveto % Move to x & y + (Resolution: ) RIGHT % Label + 1 xResolution NUMBER % xResolution + (x) show % "x" + 1 yResolution NUMBER % yResolution + (dpi) show % "dpi" + + % Resolution dots-per-meter + pageWidth -1.5 mul add % Move down... + + moveto % Move to x & y + 1 xResolution 39.27 mul NUMBER % xResolution + (x) show % "x" + 1 yResolution 39.27 mul NUMBER % yResolution + (dpm) show % "dpm" + + % Interpreter Information... + pageWidth 19.5 mul % Height of interpreter info + + pageWidth 40.5 mul % x = pageWidth * 9/16 * 72 + pageHeight 35.5 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 1/4 * 72 + 3 index % height + 0.5 setgray rectfill % Draw a shadow + + pageWidth 40 mul % x = pageWidth * 9/16 * 72 + pageHeight 36 mul % y = pageHeight * 1/2 * 72 + 2 index sub % y -= height + pageWidth 28 mul % width = pageWidth * 3/8 * 72 + 3 index % height + 4 copy 1 setgray rectfill % Clear the box to white + 0 setgray rectstroke % Draw a black box around it... + + pop % Discard height + + % Label the interpreter info... + pageWidth 40 mul % x = pageWidth * 9/16 * 72 + pageHeight 37 mul % y = pageHeight * 1/2 * 72 + moveto % Position the text + mediumFont setfont % Font + (Interpreter Information) show % Show the text + + smallFont setfont % Font + pageWidth 49 mul % x = pageWidth * 11/16 * 72 + pageHeight 36 mul % y = pageWidth * 1/2 * 72 + pageWidth -3 mul add % y -= 2 * smallFont height + + % Language level + 2 copy moveto % Move to x & y + (PostScript: ) RIGHT % Label + (Level ) show % "Level " + 1 languagelevel NUMBER % Language level + + % Version + pageWidth -3 mul add % Move down... + 2 copy moveto % Move to x & y + (Version: ) RIGHT % Label + version show % Version + ( \() show % " (" + 1 revision NUMBER % Revision + (\)) show % ")" + + % Product + pageWidth -3 mul add % Move down... + 2 copy moveto % Move to x & y + (Product: ) RIGHT % Label + product show % Product name + + % Serial Number + pageWidth -3 mul add % Move down... + 2 copy moveto % Move to x & y + (Serial #: ) RIGHT % Label + 1 serialnumber NUMBER % S/N + + % Draw the label at the top... + pageWidth 36 mul % Center of page + pageHeight 68 mul % Top of page (15/16ths) + 2 copy moveto % Position text + bigFont setfont % Font + (Printer Test Page) CENTER % Show text centered + + % Draw the copyright notice at the bottom... + pageWidth 36 mul % Center of page + pageWidth 14 mul % Bottom of page + 2 copy moveto % Position text + (Printed Using CUPS v1.1) CENTER % Show text centered + + pageWidth 3 mul sub % Move down... + 2 copy moveto % Position text + smallFont setfont % Font + (Copyright 1993-2000 Easy Software Products, All Rights Reserved.) CENTER + pageWidth 1.5 mul sub % Move down... + 2 copy moveto % Position text + (CUPS, and the CUPS logo are the trademark property of) CENTER + pageWidth 1.5 mul sub % Move down... + 2 copy moveto % Position text + (Easy Software Products, 44141 Airport View Drive, Suite 204,) CENTER + pageWidth 1.5 mul sub % Move down... + 2 copy moveto % Position text + (Hollywood, Maryland, 20636-3111, USA.) CENTER + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageWidth 6 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 59 mul + pageWidth 6 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: testprint.ps 985 2000-03-13 18:55:00Z mike $". +% +%%EOF diff --git a/data/utf-8 b/data/utf-8 new file mode 100644 index 0000000000..41459ae14f --- /dev/null +++ b/data/utf-8 @@ -0,0 +1,38 @@ +charset utf8 + +# +# This file defines the font mappings used for Unicode/UTF-8 text printing. +# +# Each line consists of: +# +# first last direction width normal bold italic bold-italic +# +# First and last are the first and last glyphs in the font mapping +# that correspond to that font; a maximum of 256 characters can be +# mapped with each group, which a maximum of 256 mappings (this is a +# PostScript limitation.) The glyph values are hexadecimal. +# +# Direction is the string "ltor" or "rtol", indicating left-to-right or +# right-to-left text. +# +# Width is the string "single" or "double"; double means that the glyphs +# are twice as wide as ASCII characters in the Courier typeface. +# +# "Normal", "bold", "italic", and "bold-italic" are the typefaces to use +# for each presentation. If characters are only available in a single +# style then only one typeface should be listed (e.g. "Symbol") +# +# Each font that is listed will be used (and downloaded if needed) when +# printing. +# + +0000 00FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +0100 01FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +0200 02FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +0300 03FF ltor single Symbol +0400 04FF ltor single Courier-Cyrillic +1E00 1EFF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +2000 20FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +2100 21FF ltor single Courier Courier-Bold Courier-Italic Courier-Bold-Italic +2200 22FF ltor single Symbol +2300 23FF ltor single Symbol diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000000..691498a451 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,152 @@ +# +# "$Id$" +# +# Documentation makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2000 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 .ps .shtml +.shtml.html: + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --numbered -f $@ $< +.shtml.pdf: + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --numbered --jpeg -f $@ $< +.shtml.ps: + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --numbered \ + --jpeg -f $@ $< + +# +# Document files... +# + +DOCUMENTS = cmp.shtml idd.shtml ipp.shtml sam.shtml sdd.shtml \ + spm.shtml ssr.shtml stp.shtml sum.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/accept-jobs.gif \ + images/add-class.gif \ + images/add-printer.gif \ + images/cancel-job.gif \ + images/cancel-jobs.gif \ + images/cancel.gif \ + images/classes.gif \ + images/continue.gif \ + images/delete-class.gif \ + images/delete-printer.gif \ + images/draft.gif \ + images/hold-job.gif \ + images/left.gif \ + images/logo.gif \ + images/manage-classes.gif \ + images/manage-jobs.gif \ + images/manage-printers.gif \ + images/modify-class.gif \ + images/modify-printer.gif \ + images/navbar.gif \ + images/print-test-page.gif \ + images/printer-idle.gif \ + images/printer-processing.gif \ + images/printer-stopped.gif \ + images/reject-jobs.gif \ + images/release-job.gif \ + images/right.gif \ + images/show-active.gif \ + images/show-completed.gif \ + images/start-class.gif \ + images/start-printer.gif \ + images/stop-class.gif \ + images/stop-printer.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) $(DOCDIR) + $(CP) $(WEBPAGES) $(DOCDIR) + $(CP) overview.html overview.pdf $(DOCDIR) + $(CP) $(DOCUMENTS:.shtml=.html) $(DOCDIR) + $(CP) $(DOCUMENTS:.shtml=.pdf) $(DOCDIR) + -$(MKDIR) $(DOCDIR)/images + $(CP) $(WEBIMAGES) $(DOCDIR)/images + $(CP) $(DOCIMAGES) $(DOCDIR)/images + +# +# The overview, admin manual, programmers manual, and users manual get +# special attention... +# + +overview.pdf: overview.html + echo Formatting $@... + htmldoc --duplex --compression=9 --jpeg --webpage -f overview.pdf overview.html + +sam.html: sam.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif -f $@ $< +sam.pdf: sam.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --jpeg -f $@ $< + +spm.html: spm.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif -f $@ $< +spm.pdf: spm.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif --duplex --compression=9 \ + --jpeg -f $@ $< + +sum.html: sum.shtml + echo Formatting $@... + htmldoc --titleimage images/cups-large.gif -f $@ $< +sum.pdf: sum.shtml + echo Formatting $@... + htmldoc --titleimage 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..c60f26102e --- /dev/null +++ b/doc/cmp.html @@ -0,0 +1,672 @@ + + + +CUPS Configuration Management Plan + + + + + + + +


+

CUPS Configuration Management Plan


+CUPS-CMP-1.1
+Easy Software Products
+Copyright 1997-2000, 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.1 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 5.50) and an image file RIP that +is 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.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

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

+
    +
  • Adobe PostScript Printer Description File Format Specification, + Version 4.3.
  • +
  • Adobe PostScript Language Reference, Third Edition.
  • +
  • IPP: Job and Printer Set Operations
  • +
  • IPP/1.1: Encoding and Transport
  • +
  • IPP/1.1: Implementers Guide
  • +
  • IPP/1.1: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
  • RFC 2567, Design Goals for an Internet Printing Protocol
  • +
  • RFC 2568, Rationale for the Structure of the Model and Protocol + for the Internet Printing Protocol
  • +
  • RFC 2569, Mapping between LPD and IPP Protocols
  • +
  • RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1
  • +
  • RFC 2617, HTTP Authentication: Basic and Digest Access + Authentication
  • +
+

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.1.0
    +
    +
+ Beta-test releases are indentified by appending the letter B followed +by the build number: +
    +
    +major.minor.patchbbuild
    +1.1.0b1
    +
    +
+ A CVS snapshot is generated for every beta and final release and uses +the version number preceded by the letter "v" and with the decimal +points replaced by underscores: +
    +
    +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.1.0b1    First beta release
    +1.1.0b2    Second beta release
    +1.1.0      First production release
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +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.1. Failed tests cause STRs to be generated to +correct the problems found. +

5.4 Release

+ When testing has been completed successfully a new distribution image +is created from the current CVS code "snapshot". No production release +shall contain software that has not passed the appropriate software +tests. +

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

B.1.2 Documentation

+ The top of each source file shall contain a header giving the name of +the file, the purpose or nature of the source file, the copyright and +licensing notice, and the functions contained in the file. The file +name and revision information is provided by the CVS "$Id$" tag: +
    +
    +/*
    + * "36;Id$"
    + *
    + *   Description of file contents.
    + *
    + *   Copyright 1997-2000 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:
    + *
    + *   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$" 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 "36;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.1 */
    +do_this(float x) /* I - Power value (0.0 <= x <= 1.1) */
    +{
    +  ...
    +  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..3b7b93abb9 --- /dev/null +++ b/doc/cmp.pdf @@ -0,0 +1,765 @@ +%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[11 0 R +]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[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 +]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[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 +]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<>stream +xÚìÏsë8rÇIŠºÌ‰öŒî´üt§çyšÝ­ÚJñÙfvçÖ$ÁÊ!•S*Ç6•üÿ±~X"H€èn$è5¦jêÙE|ˆÆ·@ƒúÇOßòýÛßò?=å¿ýžÿçÿô,~*ÅOÿÈÛÿù×?þøÛï¿ÿºÏÿü—_Ÿò§§§·kýñõ¥ù÷¯|­ÿöœþº?•ßNå÷SùË©¼œÊ¿žÊ¿üÇ×?òÿýŸÿû¯¯ÿ–ÿíÛ׿ç‡oß¾>ÃKþ=ÿãõ§öcøä²+âõi»Ý>ÜËÛ?¶ß_—Î%^¶wY¤*w÷¯ËäOj¤Üöû¸ē‰é½Ü?–KáÂC]о/ëå!"—x[ÎõœE¼r˜ë‰KåÒ!˜¾rÛg޹^òȾü\ÆÕÊÏ3s=GžJRÎÉõ-òVâÃl\ŽuЄõV¾ÌÂ%²( + ‚B¹ü29×$X,0X –€Åƒ %ƒ/° ¬(ÚMÄåÝoÙ9h6×ÄXo`å\ûhò’LÀõ#𡬼sÕÑ,åÏ\M6A!|…gi,A +Ú Ñ ê£s5Ѭåà‹+›— 9Ä`™ãÅ`ž‹,öD.1?V{àÊàŠRç\uD98æY\‰c®}HÙ8媣`Jé++D91WT蚐°ŒÒË TÔ  LÔ‹Š4ðZåªBÃ2t,OãQ ÔxŒsÆq‰±FãzX¢Æ#F,Ï%£FL×]w÷Ûí—×cy>|ðÛa0IwÅ÷_†ƒüxÂ[‡ÿîŠG’þÅ˃ŸßÝuoœ*=[ í,¸ö~ºªÛk[ça=xì.Bú±àæØ\ìPƒ–.Î$[q¹¸¡==·aMJ&³»XéԜ.K™\¬@ž› É貘ÇUùÑv‡]¶cqeSÙà՛eN¤ܯjؤ½s’  ®|²¡ÅϼJé\Í Xd°˜ÎEùØÍÉÜZ9ƹfÂ"‚­¨\Õ FÈ1ŒȕυEÛи'’ –Y¹0p7ñú¥uZj+Cg‘¼c,Òé« …«rÎX•½ÅÍÁ‘jÄ¥{.B J<—°ÒlKÃ7D=Ì:¸ÎåÛÁÉ %i=•œkˆàBf½ .Ú`Ø`¹Š¹2O”,Á W­Ç’ó ìÍПR4q‡ãÚa…„–¤8®´&1Š«žÙ#3ì€á«aÚz/8 [c¸²0Dƒ¢õ ‚«æfóuXiæ*B J‡íÌ\Y OjOjäªÃê.d‡%F®"°îBú°ÒĕÖ]È'½1p5Á¸dZ“RW\wá¢ÄÄÀ•6ºÐRVŽr‰» 7æw£\u€Ý…[FJG¹*OŠ…²¢d”+ (2$*ÇVå'ÆB ÃRåÓ©¹Z’ Wå“s! q5ÂÀÚÛ=W¢È£­ÔrAˆ"v@;-W¨jàLi­ã¡ªnè¯t\5-4”=Ùí§ž±¿ÿ.Ï´’T¹Æúù=¾aÀ +¢6(®–KH·Kh%ºÖRÕÓbQ®•–ër›®Îa‡Àà ¯Çé¹ £^ >ÜÌіœáµCrí´\MçùÖ 1£$UsÑys¥Z®³í%·NH)}¢æÊ‰Îkœ+ÑsÝ´BPf=ègŒàp‡åz7.×MÛk¼b”¾Tq5ÔÊÀµÑrÝD° ¬•T؇ô¹WŠçZ鹊÷G”Q&ß V<זByW¤çª/ŸÕPÌ1PRWF4C#×NËu¾×úü+ü’QØV +.A5C#WªçڟòáªÕr[¬àª©fhäŠõ\盽§5Rì•K,×êZ[Éu6Ž;êÊ12BªWNZ,×:{—'%WG¤(³ÔgO@• ž«x j®Š5K5†ˆëWC6Ãq®ZÂp ÖbI…Ó5 ÊFÒâ¹Ä»Y¨¹®&EZ,ip-â\9%pžê¹*֚Nè(; +\n£á¬5;c+\ŒôÅq®æ" +®K‰kvª‰@“¤¥pµ¥×qgéB™ÐdcMãº(½Ž«àôWòD@“ë¢ô:®Œ3¾êÙwCÅuQz WÍÛÃÈ0’ ¤h#!r]”^ÃUðûMÏ%s Æð2r•^Õñ6g +ÌÃ’lì¨\g¥Ws5Ì]Œ +㘁´¶ÑR¹ÎJ¯æ½ØER2WÁ^f®“Ò«¹rfæŽÀ8f DQ)ëd݅~^¹e¢IàkSYŽ­\§Öç*®³Ý Fȑ#š ”(ªT?º²k ±ÌukDŸ+?krN7Ä="àVÌµë>š>h¸Þ;а›‚]†Yw¹k6+IlºŠšô¸ Wuáiè†X!dr¸Ñ˜ÄjøCýsȵèÝJ´§•¸rŽlH[âã‹:\…’K\[°'¢@Ø¢C­I¤€]Ÿ«VrU×Ê=öEèà£ÃDïû¯´ùÖṌŸêsí¯#èùVž«áxåÛ-â;^WÈ\OÌɱonn0¾d=äª\ÝT”‚lˆ{ó€¼0ÚT¹WWojò$ ð\{–l lbÕ¹.¶*qeÝKž„‰×ñÒáÊY²Ñ˜×Ó{Šyq—KΈÚ{ÈhzªX¯üPy8Å:F—« »òúh9ÔNþnï5ùÒ*¹Ä€+“,¯ñª è¨Wo'ÍéŧñýGH©\SßËy°†ÇeŽæãvQ°2Ÿ,’+çEQÁse¼(*t.a#‡s5–r*W͍çª>š^¸ +vt6מ͕4™¿peM/\œ¥ùp‰'óg®úÃÉ<–k2ߝÎ-‡͋ó·•Ü:\[æ»uîªßFwÒ²ßmµwpœOm›.Ò,²Î-ï\·u›þà,•\×FÍÕI¿\¹r¶ûRãkT§×ćk¥äjÔûËÛ}©4fÜkbÄኔ\¹z߁¿h£¶W]nj¯‰;×NÁU UPn9Ár­4áËNŕr¸RW6|ŒŽ¹Î«Ëë51áp%C®wшﲫÝÊ-§h®š+Vqõó¡¸g¯r~ô'/ÙÅlp\ëQ®Ó¿^òHjÁZv,¥Šk£tEr<Џ¨ëdÞ7ÛnlÌ\—᯻?"éx@·‰+×à¢Zr—Ûj{‡àꤥÈ]|Ëíé71âp .’7.y<€ +£®[‘"K~­lâŽÃÕ¿(—óM +-áðì8—Ðpz®”ÃÕ¿¨7RNf™*Œj1\·Ùÿj®˜ÃÕ»¨ðTà¹b\Šã|f.ÅEußÁnßÊ#`ÂÃĞk¨Šã|f.ÝÀT5_ŽÜp ×^­óŠã|®áE…ÒÁ&ŒJ[=Ì®9·r‡Çù\Ër¥#Bq­Q\µÚ՚8JqœÁ5¼HËU;â*”ñÆË- é5qxœÁ5¼(S:"×Ã%¢"ÎSÇù0\ƒ‹´\?Œê´áò;ô¼RqœÃ5¸¨[ývGסµœm”MçÃp .Òr?ŒjÕ£YU4ñ"Ú4®þE\-š+Uý6.5MìçCqõ/Òr¹ê^,ÕMìçCqõ/Òríùáa«68Íòþ ‰ýã|(®þEY/Mõʕ;ãŠK W'T•šØ;·ãê]ÄçJ\ñ®óۋ_¾,{lÔMìçÃqõ.Ê;Š-qen¸:ù‡Ýxã¼ì‘ª›Ø;·ãê]4ˆ£*,WÚâæ)­Š«ó~(EO¢Må’/Ú÷#¢âÂùåªÇ¸äã|H.ÅÀn÷X®µW£‹ç¯AeNä’/ªúC%;s Ï\BsŠCqœÉ%_T÷$[DX®W;Ê.é"Ñ Í« ¸—|Q&°üÂeÎ=Üy䒎óa¹ä‹ +E2þW=/WÁá’.ªn»Ê·EÞÙ¹j—t‘è¶²¾Æ6ÓJ\‚Ã%_”ßö¿ž#W铫{œÍ%_T ö+Càª8\òE½H0?qÙL—Q\Ù8WÃá’/’gÆé>®Îq>ès¥”ºór=ŸÞa?bšK©;3×Cÿøšü²¡ÎæuÕ»ꝪHqPJÛ:k®|¾!çéw·§†u\y1Ô׏áŒF~™WsÛìø9QeäÚÉÔ—Pì(É/4¬®KüuòÈȵ™‚ TSë¼;Àz齺 ®u+ M?\™j« ºã “Òdúu\©l)^¸š÷§»nÝî«ko»õʺ ®Dºµ®êºQ(¾unڑÀ[v…².Ÿ«öÉUtv¬÷7ïÒqY·äsM]Õ2¿ú®òöNå“+ª›v^Ȭ©K㊯ۧoƒ8ñƕu—áòžÒߌ§©KãJ®£0qÙÄóҟá¦×VËIÚªº$®Õõq¼=™t®êöÓ5ä$mU]WÚ}tk;.CúáõÏÍÝ[ÙtĪ윑Ò×%qÏ]ÓÆ+W¢ûѧ“T<¶ÔçÊ/ƒô8„wÞ¸2]:ÎeO¹éÀd#©;x®ýåóŽŸ|ðÆuŽš¸1‘†‘¶.‰«¸ÈÐÑÒKo\—½Îûƒ:À:eR¼Ë¹¶.‰ nÙ¯qëë¢Z{þ⇬ã‹õu•\ÃÄÎEu¯G÷叫“Òkmñîm®¾X_—ÂU_ `ü`;®±}½n=é½ÄÕ0‹V[—ÂÕ\~<ºeK®±}ØByŽCš—ƺ.]_ˆ¾ç²Ú_ÚÌÒ|Õ¢¯Kàj/Žùô[\½,Ú¸ôdЍKá:;æ“[öÉÕyіL¡ú’9]] +×Ù1×'ï“ëý ì —J•l:ZÇuvÌõ©¾—1ïë9Sš\ùPÔuñ~ùäËãÿc—‹|¶—‡á¤¦ÒLrTu \ÕÉOnÙ?×­µ«^(u@Õ%póÉ-OÁõ. +‰vЌÕ%póÉ-[raß-Z‹ÁX]—x÷b멸n‰×f®^]×Ù1ŸEr”Ë&ûø*™ìе\cu)\o&˜4·õS/\²{ãb§®.…ëM2âúì-¹JÜú¡k¬.…ëØÓUt}Q7®D²­x”KW—Âçð±‰ËæÜM.ý9Õù±º®ê|²&±çڍO¿6ÝyÈJË5V—ÂUߜº7®ªÛŸûÞmz«Kájn³Q.›sˆçkãï·M­–k¬®!ž—Þ¶%ä]A ®qö¶ ©Ÿ,ŽÕ¥puÞ ë«™«õ¹F꒸r—Õ¹ìf¤jŸk¤.ƒ«´çZãÒmú¡ÿ VÑ×%qƒßxàjô +3àj¸ëQ2\ŸÊ(—Õû7䵘_ÚQ.}]—îý¬n¹:}l \Úº$®úêÓǹ¬²Þè!Ón”ØÔµ*–ïí¹Ê×ëMóU|–ïY +¶X¾ë“kz.ó떗ÉUüÓr•‹ä2/pÉe3aþ䚞Ëjb¹h®õ"¹Ä?-WºH.ólõA¹’ere0ðµü>ŽO®¸ö0ðÅ}Ïn‘\ðA¹ª Z~¯Ù\Åô²×å÷ÐÍULMÞá¾70¸@ªrÃ\ e’ºÒò{9ç*Š+[\Àa +%°ß{ZÀ‘›ì ù=Å¡­´e&=@~¯thG„â‚¥Âèo‘ßoXÀQã¸÷}ô•±mç˜Á8lc®Á9æ½Qæ#/Á9°Üè–ã‚s`™±Åš3‡}€²×ÀXcV@éK`3Ëڬހò9°ÊÜX@=€ÀXa6.@l`3°½9êT˜ËÍ"8á Kèmœ£ Jè„m®gƒú¡€S˜ „A:àª%ô¢©€ìڐ„>G˜ ‡bH}fv_ï\bAB/0Ò -Vè׋‘Ã]‡+_Ž V˜Ȑ+ A,0 +-V裥ÈaÜ媗#ˆ(Â-ôDˆ *âƒ-ôéBäpÝåB} Â(»‚-ôÇ¥€VÏP„#C̾:\ÕB")£œ· Å }ºÙHd.„Ð'‹TæB,Ýċu+_†pd8üƒ"âȇxà B8j¤—Â!Gl#´A `1Û¨«>BðÌØå +h)‚¸xí\Åú,(ÖCéÑg­¡% ÇÜ ýŽhIÂ1ó3?ú•‚+~€áï€d¼s°=z @KŽy>r’s˜y€Õø©bå™a÷H*:sˆH؇–(30Ê&ÐúyÖ9eˆιÈQDs‘ƒ²Ôā9£Ò7”AОQéI+Ò@½t>¥Ï)Mª’ζÚ&HšÔ¡9›!"li¥åڇkˆ´åhél¨vc! »ô™ ±¢g83âžö¼nų¢ †®@žâÌcˆñqCË`3Ĉ9qx@Ë`iˆf(Í4€ó`¦Ÿ¬Tԇ -g€M>kΩj-k€MœdY“½´¬6± +ÈcX]>±rz‹€5D'VFÔ +œéöÔ1GNÀY™8樼A:©ÔgB©œÇ Üϙ.H,8ޏÃtºc wàÊêd†kÍÁ…Tú‰:,c=càÔ4Æ €?R§é°ŒÖÛNÓaә_‚& :C¢Åqí±`»0ºk…äªé0‘qƒph­ ±÷UKó„ªY.´v†èuâ,øV­!zÕzìÓÝ ¹ð†èQ:j ›ÖÖãrfWŠØ ¬OKüñÍPË%¢¹-±±’.h­ ѓ&æV>¬­'BõÊXZ?Þ¹±´°öõ^†˜È,e \<1÷3–½í#×½{&ܸ¥rU¤s©ÍJÉ\"š LdöܹK0‘;¸)82‡i\o\´;¼•Ÿ'–‘P¬.t¬Â^¿¹1p1_uFÃÒÇàd}¡ãNSbé¥ +\EiW°/)áøf08Ô&[õ cœFwžÿf<[l2êR6W›qÀúßtŽ*OôÛø\‹+Š¿S;‹añcq€‰‹ÙaQt_zî¬ñ¹‘‘«ˆ¸ÿ¥ó/9k·6\"â—{”56¼OßYqYtØqœ=šÌñ…Ie˜>˜¹l:ìŒöªÿ짌ý¹K.ê4Li¯ƒ~/ÛÌæqµ¶\Mä¦ÜÝo·Û/¯oåe»}È,?mcÍå¢ÃœSþ#†KȵqÀe'‰³tŽ+¼Û9á +®ÃÌK_8.±´îBrvm¦(ˆ=$W›…ÄupÇU/«»Ð\¬•O_ºäj‚áÚ´.¹‚ÑzÜöžKdKÑxw gÑ q!Øý^ +—XŒÒ¸°DôÖ!‰kvKÄgиš…X!•kæø—°MäšÕ)¹/T®9½3eû‰Ê5c`OJš#sÍ6Ähi/t®™†1±ŒÁ5Ï#îí2¸fbÔ,%=pÍ`sM®ôT9×ÄÚÁÈdr‰<\)´ášRY©Ã\®éÀx™dl.FÚÏ$ŽËšk¢Éóā×þ9椰áòoŠü,M+.ß`ɧv\~UÑ&Yؒ˧ƒ¶Ê¶åòf—ŒoÍEΡö41qÏåcÚb™®î†Ë½,ڟ›pÂÕ +·¶øhß"7\o¶è®Ë’CW+Âé,—\ŽºìþІÆÕŠ'küâª-.¹ø©ÕªGw-qËe‘^Hݞ“‹Kæ–ʇìþ‹ë6øà"æÅÇ[ï¹ðÃõV^qÙññýw/·÷Æuê5ƒAÞm_}ÝÛ'ש۞¶wê~z|õy_ß\çŽ;žpØ>ÜËývûøúêý–“pÍPàÿÿÿârõä +äÿÿEŽÑÁ0…ï÷ç’DkÿÖ¡—,ÜI†z€Æº™L+]oO%âöœï;9+•L7Y +Õ |†\òT=*Õ¥³M×Þ½³Øj«[s56 êµ«ËG Š2‰‚`”óì§³r[1âAF‚X6ã"Ök=¼ppMxjoPyWßOaø‚"ÿ¼øï¸ÛËwí9€¤œ³,MÓ –}} ìÍ`üÃÔQ]«d—¼ˆñÏendstream +endobj +128 0 obj +6288 +endobj +129 0 obj<>>>endobj +130 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +131 0 obj +31 +endobj +132 0 obj<>>>/Annots 12 0 R>>endobj +133 0 obj<>stream +xڕVÛnâH}ç+JyJ¤Áksgކ܄4™eŒö—Æ.ƒ'm7énƒØ¯ßÓmÈe¢AQ¬´».§N*ç¹QˆŸˆú-j÷(Σy㯻!µBš§¸éõ;4O.#šÅjÃWó_þ6êW·Í^´ü}Ñ8áÂfi ›©¢2íPÕ¦­^àCÍי¡Xi¶*µ7¥\bÅ9Üi#EA‰ŠËê¤Õ6Kؐ]3­Jü)³ÇTiJxËRm¼(É +‹_QÄL*uù‘5jW]€k•çÈöøcü/M4¬³bE³½±œÓâòâúq2»X\ÑOÖÆ¡r5•ڝм«¼Vå8êoYo3Þ}Rúç ^Ê´Qڊ¥d¼«m¤Ø³ö•;ßE«Û#tÄ1ˆK㘀ƖÖÂ8·óF„è®{Dî1½§Ap»Q Ϝ¢p\ÕIÒ̵>ıflÉ\H愖{úmÔÓ@ۍ‚ÁIØìO,`? ƒö¯]ôê¼Æv+̞fuo@£JÊØúªžaíyIV9fseÄ ±‰5J–^†Ž[!e՛-‰ÒÆIËÅmz/r* D“Ìk‘֝üé%9býĒ÷{'M§^BZÖ©ˆÙµHúðẠ+5vvÛ£LP¨U±’Pëøv~×O&Ы¨Ì—ÂdÕdøqrö¾Dú¥–¾ z.¹DR‚ ßLÇw‡Ë§Än;…..¿On¾Ðôî:ŠúÃÅÕšAÞ¸`c0®4’*~‚Ùìaän]†o›Í /ÙO®‡ŠÌ萐F½IiʍÓ8”µËìš4£…8¤e»f™Ùý‡üˆ$1ZvJ?UÓR«q%;eì,ÖÙÆkbã_d¾°‹Éä“Þe|"åïÁæo°¤„¼2!±ÙÈzÓ*‹„«±ü1ªG×cYV³—ƪ<û¹·õ®Q)Ýÿx¤ûõúâ2.µÆv“{ª€ªô½U7膋«7x X£YîڔfØ"Óñ"– ‘ÒÅÂLª*TÑ<¡¬¦Ô¼_ySëW^›n+ú–ÞgûþeÕÃHé•(<-@ ¼¨S%¥Úù)e¯ óµJ׉Z7–‡\‹V¯O¯‘àÓÕ<ýxÅG„º>òBPšrÊhõ,×6\ïé/ežå߁ÿ\«Òmÿ)ûaðÂ ü¬H]WúaKN±‰ £ójù†÷Raàõþ,ǯUâ:7åç2Ӟ‡:ù ¶jV݋†Ýú¿ˆc£:ƒ0"‰{[wþiüu.“Ëendstream +endobj +134 0 obj +954 +endobj +135 0 obj<>>>>>endobj +136 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 +137 0 obj +117 +endobj +138 0 obj<>>>>>endobj +139 0 obj<>stream +xÚ­–Moâ0†ïüŠ9v%HI r£PZVE͒´§½g^%6k;jù÷µ>ʖJZqçyçãQþ6|h›½:!Тq“4.'×´!É̝°×…$½`ŽJäՏä;â÷ª#­Ð÷wÈóaôÅ0´,k¢™àÕñ.øþöxzŽ™¬2‘çâ…ñeõ`úþA` +äN5…ÅôÊ\ڝT`º}Ğý;{p¬|aZ£YÔò=PéÏز”•ÞŒp²Dˆ('ü˜o÷;UžŸÂ§ãñ;x¼Q ˜r2#aŒŠ-¹ý¢’­µ©#gVÂ{݉ˆL¿‰0L ƙÒ&!•Í¥$ùüãvôo =šBGR,%) +k‚³£Žç§Ð1ÒR2½1æ] ©Ïà&Ñ)n‚ê\‹ÄOŸôïIáWÚö<>}6TëíÛÍo«œnÛëW3À£^¡Ü±úÏ悷ކX à;'x˜Š…1ŒP:vÉï0;]ﳃ Ë&BDC¼FÊ2FÝ|7÷Åèz¯V??¾,Ͳ8¬Å&$+&S¸M™«ÇŸFÑ~Šžî“ŠQÃã«å¤êò.oo9©íŽ'’pU{ö¬i±ÎÝv´F½+YŠçqf"ÅÜcA¸f´^róÉÈüì]7áq>>>>>endobj +142 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 +143 0 obj +122 +endobj +144 0 obj<>>>>>endobj +145 0 obj<>stream +xڍ“ÍnÛ0„ï~Š…N ਖìÚNoMœ>´h+ÕÈ!šZIl)RáOä黤”pš¢°&´ËÙýfô0É`F¿ V9̗À»ÉU9yw{ ù ʚÞ,W («³9Ü +‰ð‰)Ö`‡Ê—?b]¶ê.–YšÇÊ4ƒ0ȝ6OP8ã¹ó‡údÙXŸ/Óxó ã-Xí G¨ƒ†m™”°Gè%ãXë÷՟+¹6m¯U%TNƒk©I×îÀ ÆZûdv Ý"µj,U}RÍæÃ”÷g‰å-V^¢I¦H±ç¾·ôOïÏ¡Ô`°cB‘^×3'ö4ÚA¸´¬ÐÀ÷ÏÛ»8ï f§pœP±í¸‡ÒîD9ÒZÑn™aÜ¡±@:UãÚôØÅ,]`s(NÁ û&ÑâÓiVšû`\ ª*¨µé˜‹' ZnĞ4ÇǾGbûWS¸Öò7|ð´]h·ÿpN ª7L«WqùïaGë½ +¨ƒ¿\+g´]Ç#ÉpO1Pv„´,ƒëäìõ®HÈ—L¤#¶N$Šÿ$ƒÑ’I©&ä‹t™ƒŽ€Ô‚Çõ,p¦B«#©3^VیÄôÄÉwÅ1¬"Ï¥¯H6J†ŠC+ö¬GC¹ åÛíøBI‘¥x~ã'mð彚ÉhÓúH|¾ÊGŸþö-/Ö³ô’Êèýûp¾)'_'¿{žMCendstream +endobj +146 0 obj +544 +endobj +147 0 obj<>>>>>endobj +148 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 +149 0 obj +118 +endobj +150 0 obj<>>>>>endobj +151 0 obj<>stream +xڍVMsÓ0½çWìpJg¨iÒÐn¥À '  Ã%Å^×bdÉHrBÿ=oe'i\\˜~%Îêí¾·oWý5™Ñ¾ft9§ó ÊëÉûåäͧkšŸÑ²Ä'— ZSüò®]¦;nœôÕ»œCÐöádù'4›u'NçY:sC÷®Œ[åyxx5}u¿¼{µ:¡P)chÍÚu­cä‚xÃþ‘¢®™µ=9O¶þðf‹Ôø°ñ µ€´³ól.i·:V+¦Ûï_ï)ô%dû|ªçQW­´øAZmX¨¨Ö*0%g™\™°JgŒÛ‚-…¨"‡w’tþö@v–‘<š‚é@¹q  &wuc8JæàLµ³ƒ’磇]ǏSyÔÄ,Žcè(,VSË[’‡PU…xe Bé|­ä©ÒFA²Õ‰@œ>¥;sßǦóÊoÅÏÄã&dc®ivÙ;fq–]uÅÎèÖ(تԹÚ1þ«¹~T, ‹GuCÏ9C44R݆(Eå=&žªø÷¶ØÎŒ·õ޵ °RLh+ÖlãH?¸¼•;Ù{çGZ÷݊À„ƒÁ¨Ôf¬‡Ã`¼PÝKâ¿ÃÇ·1ÏÛ -B0ýh¡¯®5PÍ'B°±¯Ó¼¨f á\:ØX«¼Â‰1Ë?µ„>>>>>endobj +154 0 obj<>stream +xÚuASà …ïüŠw´‡`ˆ ¤W;õ¦SGü4'%i«ÿÞ%ñêÀ°3û¾·oùb5Un7²GÃƓ¢´æ +¦¿“\â%ÍÁ‡ÎÎ!ōù PBˆ¬Eæìp™\FʸºØS âbu=ng1ãÃwìՆÁWøàé3'jŒ¸Ù ¥a=Ž?ëP—sÊ| oÿ…Լ…jé¡üÝûá »}8]ò²*žm´'7º8ã0Øeõj5Uº©‹©-=)$oPÿ÷Û½a¯ì¤ŠYƒendstream +endobj +155 0 obj +214 +endobj +156 0 obj<>>>>>endobj +157 0 obj<>stream +xÚµVMSÛ0½çWìpjg°k‡HoÀ@§—NJ\®Œ,¯1¶äJ24ÿ¾+ɉ‰óÑöÐpHlí¾}ûöCü¥Ð_ +Wc¸˜¯G·ÙèÓÃ Æ d%L¯&.a¡JûÆ4Â#VÈ šÙ‹·L¯‚e4Mã±·SxBm„’ð­­sÔB.ƒõÒ´³Oc|÷c¾€–ð€]iĨaÚÂk =¤·ÌbùBT…«@c£Ñ ´ä‹P³¥Ï¡Ò}1Y@Ã,_‘•§ì8Päô"ð Ðæs –ÀÌ1#¢±'æÁb{˜{_»ó4Nãd7­È{w‰Ý¢e‘Ec7á)C’OȂèŠR„\XÓ ,H Ÿ@…ÖR¶·PªªRoÁÄä­¨ŠNŒ¿&œ{¯C´óôñ¸{Z€‘¬1+eAX¢Ä ~©4 Õf 9¥ç%.…dÕ&GÿÆWÓ±‘JűØ&5(G—ûÙë™yvåA +䢦ÒWñŠñҒ–ÚpE-pL”×ô9yîò}§Bx}B„{F}ÃWL.‘X0 …è[צ%k+ÒEÒO³™ +Óæ‘Y‹5p5:²ŽÿN vRÄðµ$ï€?Ё•¥ã|·ð±” JðóBg2t¼«öœ¤«*ªOO„Ôr’î±98àʺáJ>>>>>endobj +160 0 obj<>stream +xÚmP½R„0îyŠ«´8$¶Þh§sz¨õ,Gœ`6̍oï,,œ¤Úý~÷+QÉS°+ãoÇä¾Inï@UÐô²)«*-¡é®nÓ^É2]7Ÿ‚)@©³ÍKY +æc 8h{†N$ƒÖ“¡@ðܶÄÜÏÆ|‚¥ tšƒ×§9hgAx&Ð ­'Œ„Þ»Â@ÐÎޓ °?Š^·DcµKóh¼a‹.lRxv0y×Íí"é×ÈÀ#TP[`ׇ zm KRëLÈ,¦Ñ'ј¼–ÀҌӵ}ýÛ^UZC½¤Ø¿ްw¶×çÙãbÿ„V*1úÁ ÜíJÙVyI*‹Ã"¯Ódÿú¡I^’Zƒµendstream +endobj +161 0 obj +285 +endobj +162 0 obj<>>>>>endobj +163 0 obj<>stream +xڝ•ÁrÚ0†ï<Åۃ Ò#q q‚:vfzòâ¨È’+‰Rúô• ¥0S+ÁãíúÛýW¿ÌN=÷ a܇ÁXÙyÈ:wÓ/ÐïA¶v‘ÑxYþi3¡Œ¡zÿ9ûÞ$„ãCB0 +»ý&¥B†º4‡Œ„aá¨AÔm(Ñ!4< …ƒãÓÀTYm-jT[Z`÷œ§WTS!P´S”9—( òŸõœZ +¥ÒöJ'{Å-Pwå¥¿ ¯Ð×½’ìè¾VQn%gÔr% 0WF¢€Ú¢»SPiUhZ_9ƒšÓ©»A“QlƒÖ§ÊµÛ¨’®}¥7-꺗žœ—‚a¯{pE&L+¹÷c’FIâi¤tã`nÃRKeNu‘ÊÖN}"ݽlúqߝ}êž +ô¨Ž^IÚ^*r +êõ%ùDsiëÁ¦{c±ô0ã4º#íИ¤Ë—ÿ4ß@m<äiæáN¹@È4•f5MYŔðОH0›·óžp'ÐڀP¶©iZ½qf`~<’~4‰n`µ»aH«•¸¶ÄóJ<«Õ5ø$ΦíðÆ\î@, .ÑÒ#£fS¥™—KÈØ“Ù®ØÆ$]¾GlN'ÓXê‚Jþ» xØsòØÎž;å§±>R,½¨E²ˆÛY‹­¨_P9§p‚rñ¯wϰ×iÄmó-¶">ÅD›2Í+ûO7šfÁ?ÇtñpˆÞŸG_‹ÿ§ÃñÐ-÷ê@Ö qÖùÚù÷ªªendstream +endobj +164 0 obj +573 +endobj +165 0 obj<>>>>>endobj +166 0 obj<>stream +xÚUÁ‚0DïýŠ=ꤥ®BÄ Æú R-m,HâßۊÌîigÞtúD?R¶PÁÑ®¢€1ð2,§qü¶¹H7KµGÑK(´m[~÷nösG>!ÂiL‚W¼Yä5ìOujVBC¥´î„;ŸÝ8;ÙÖê…Ë×{_€á˜°¼6(­éTÿrbRÖ@-Œ/4H3A£… p„iæ¡(#I€0 Gš†Ç¿‡œ´õÿpï 9:£bîGàendstream +endobj +167 0 obj +194 +endobj +168 0 obj<>>>>>endobj +169 0 obj<>stream +xڍV[sÚ8~çWœñô!mÁØØ …¾,%ɔ™6Ó]H²y¶ÀÚµ-W’!üû=’ 1Áff¥sùÎw.òïŽ~} B”u¾-;ýû1 R–S 2!i ++ +¤(R†½336gŸ?×]ñŰc*Ù㯅k£ƒ?ª¢ =÷‹áÄõaa•ïµòQ0¬ÿð,(ˆ¢$ÃPZ9›"¨(9Éêø}ÌNB‰¸”‘HþçĊqÑ\–BóžHҊ¥Lím <©€Ç‡ù?ïø2®öRÑLº‡`¬{M0a¹f]æ‘&ý€&![ä3úŠ)&skpÜÈÑ)ƒéÃb^ы{¯¯v™~纬 :|®Dé°Ç=£=ÜáöÜÖËæRÅ"ƒ…6JI”œÔ¡PñJ4›¶Õä f“*­ª×Z¥kVE) +ŽÕˆÑçDéÌX‘v¬^ċ½`›DSé€ÑSή»f×x:¦¥ÂfÚé…eµ²øPígA·ÌPYoBVk‚ÕÞX›=-Àù0?8 ÈfbIô`¬9Ä¡Ñ +ûŸæ«þ€OàïZïìä\à–ÊH°BUÉ5È«6—îUfGæüñxÔxž§c¸#rÅ½V;‚Iø%x\FJvÍ0â²É˜ÀI"¶4¾Îõqä™$H%J››.H,=;ýlêt{–ØÄšæ ™DÕdÒԐàØÆHHsƦÞ@QEq:è´5™»§Xµ$­•WJv.ÒÎ-[•†wm¬Ä@,-Æ./•¥q“ÍZ¹óc>»{XܹêU9°K˜n£„—il›wE©®4ÓÛv¾6hËæë·G]—“¦°¡b’‘ š)RJ¤-œŒMÛXS“«òª?S¥ò‰¹ àDZço=Ó¦×ìºM: ýЇ)á!<1ºƒ[Á¶Øð‹’)Š7rئú§é~Çy܅ŸDìSÅ7 †½ÀÇQ÷¸˜^ëÇ'ðrxþËGFAo<ô‚Öâ5>¨,dOO‘?õÊåbÓ¦ðüü<D©bÒïïv;·UãÜĬš×¥î0ý—Œ¤w2_|÷’Æ AcpQ#hÐÎ5ú§PÏLÏÚ´âJñìª[H ýuñÂN>Žð†·&,ÃÚy»µªæÃ¾ZàÑÆÅÒÂ#RÇö˜uzÀTëU¦ÌÂñi…ˆTB”™’–ˆ/µ›xd±´¾i†£iô´ŒoêñnÙù«ó? :endstream +endobj +170 0 obj +1054 +endobj +171 0 obj<>>>>>endobj +172 0 obj<>stream +xÚÍU]oÚ0}çW\¡I- dЏõ¥“úЮSÙReœâɱYìØ´ÿ¾ë$|Œ¬íº§BŽís|Ϲ÷:ßZ!ô a0t?žµ.Æ­ÞÇÂÆ ­ #ÿÆñaÊ LHm,(d9ØU :)‡‰xÚ%|'NŒ^?rèޑ[À ƒŠŽàº‚¶ó›ø]ÛoìèUd'Ž›çè¢zõÂïÃÇBq+´2›}Q´÷>ð£z—Â˄šU›¶Ê¼þ°Ú´¡…°)0˜I=e ×s“2)I9p6–Iñc˜¶¯ô8¦Ý…rÄl5zÐڔN»–i +-÷'“=ZÉÕZ•§“qÉqÉBa /äΑÎÕË/÷ ”ÅQ07ꉊǹB5UyхÀàÃ9H!µƒ|£¨â£øß ñÝoyÈҚhYѶՏ}%àû u£-rEŒ”Ÿ³½ÕŸ/^r¸¥ÊÖñKWÜàõ+®&Ùv§P݇ð–ÎÛ¿à^ëÃÁÛú0+uücÖàÿ«k¥a4¢œ»·m©¶¼õ/µJĬÈ+Ø-Sl†¥È{ÉJ£¼ +åú…‘›ŒÂÁ_’×ãÖçÖ/x\¡endstream +endobj +173 0 obj +751 +endobj +174 0 obj<>>>>>endobj +175 0 obj<>stream +xڕUÛrÛ8 }÷W`üÒ8S˖ãK’¶m¶ÙÉöéÔ»OžÉPd³¥H-I9ñîôß Š–/R܋=c‹x€BÿvbÒ7†Ù.¦Àóλygp;„+˜g~gz9‹F0OÏç½ù—Îúñ0ºôp/¸dÖ^_§úÁ­„]œ-z/ 7:/J‡°7öŸ½¨u¼÷A;´× ´Â¶û ±ÓXfR3íÏà>RNwjÆ"ú ¬™,ñ% £!¼~CyÒOLÏ­M~!±ñ°w{¿‡ƒÅÙïi‹Gn-Äÿ›¼ ŠZ\Á +"ÄÍ¢÷ªaýæ×ƒÛ+ˆg¾G}jR¼µ½‹Æð3‚%íÎoìýa2$sðŠbøÀr¡–Ái q¼uMƒÓ…[ƒ¥Ô “`¹.ìŠI g…pLŠÿ0¥t»s*S}²ûhÍÜñZØÏŽ9<ØDÇ£E¯fyä6_!h%7€O '´§+5)åAŽoþ¾ÿ B94ãR$†™MñzÏd%ø +òÒ::¹*P#„FðÂ`&ž ËËÂv=-ÿФöŽè&ðg3î.Yƒ…¤ SH6•Š{^ØÌ,Ë•óÙ¢BR-iÖZA@µNN¶HjÞîô匴_y•*¥‹Àµ¡c ºGD*ƒ6©õ<}}Ö;BÔÈÌ܁¹æûVm¶¡(›cž!K*:«KC}ÊÄa#S¤ÛæÏt- DðnÔðÅE4­<‚?4¯*Åê*>«ã÷ŒZ^çõL4]%„3¤J’ŽB`*Ý;Š<ÇT´˜ié«YÑbÀuîÃCBÜ¿6J•¢åF$tÁ*Öñ¯CšûñÚUI’vá¨ö¯Âäò·€—Æø0¾*t'²p Zƒ%@ôçÇ4ÆÄÉI2ù¦øá™ü|м¥":‚ÅòËðË¢ô½è>¸.°¢@òJÃ@ E`°õ¯µìcÓiº®UmvËýÌ9!°Éï ¬âØ­Ø›ê8RQ‚­2÷ÇRÌNÉâ¹w®C!ýP~™¦‘c@W“Òžxyn/·éÇqL–éÕ(Ø+ˆ­2±,MÅþbŠ-±bp/Yžgäߟ†Ï¾kƳ1™+[<ñïçOï«„€Âendstream +endobj +176 0 obj +847 +endobj +177 0 obj<>>>>>endobj +178 0 obj<>stream +xÚÕUÑn›0}ÏW婍Á ƒt}Z³îmS§²·J‘1N`ÌÀ$Цý{¯ Iºdm×Mš4!|}Ïõ=ç+ß = ÓÀüD1¸Šã÷.-M$˜…îQr¦·•LäY©!ÚªYè4£Eúò<úB¨ °ÐÀÂ9¾çÎ îÊ p«ëV趖Í>Ñ7‰œ×žë÷i.ÃG^dåªKòÁXŸ4 º¤·yŽfW %/dƒ&å%rµ‘µàÄ&Ó)Ú2‘u#J»z#e‰ª“¼L0\P!xUIÊK t*A ¨¥ù4=ÐÉlÚ±7gáîlhIw-Ø +¯@!®I-Ü»óªÓ)IÑSàm!KÍu¦ÊG_s‘> Ü‘MùZ‚C¨Â@œ+ñ-’Œk™o‰ï’x[FÖr–¦V!‹XÖ{Վh&}S¤HV‚ ’/á¥è%5õÖ¼Îxœ[õiT¨Tž‰-x¬ÖòMGã`gbIŒG»czO`„ˆ„|@ŒÔ2æŸonéCż†ªŒ2{‚EzŠS†q”ùý¸–u³Åtº\0oëÚ(ÛÐt¤mÌ䜞¼Ã“žÅs}ŠÿñôÅ 1ÏyÓ îÄendstream +endobj +179 0 obj +572 +endobj +180 0 obj<>>>>>endobj +181 0 obj<>stream +xÚµUÛnÓ@}ÏW }JÚÆ‰“4n(}HC• j„©ªµ=Ž—Ú^³»&Ä¿3k;ܤ$”§ë™3sœ/ ºô³ÁéA~Ò8s#°pCò Ç‚4Ϭc˜ˆTi–jÕr?—Qƒ2ª}ÔµU”eÃ%Kx:+ƒ`ÛUPoXãüª¤,A*bdôò,Cé3…0ç:‚< P*_H È«çˆ)̅ L›{îˋëÛɛËkw|éîš~ÔÅî[=ӅÜcwà ¨}kÚZ†<¥Â¡ #„Éû«kà©F2!æždrI®45Ÿñ´ÄÄÒ5ÊZÏLRÉo›©u[Kë6\U¥%Gî"#d˜æ J¦9aÞàH‘kaŠ_QB&”â^Œ P€˜—óP>øúw´ ðŀ¾H2£´îí¯ß_m™&y.|ê›ê¢ñÎ5NDb‚À‹…·„ÇÉp¦1^Ž2?ZíûiY® #SN®Ý+Š™I—dvéÔÈô£öX“ê¾<€Î>¸W %[À~gWn2`™ÁôŽŒŸ'+j +´ ÂAå<³Ft=>pý#ºþ?cψ@‰\úf-VôåšÇü;–œš}™Bª¸;:¿0Oýòh×*_r:³Y‘­ÎÄC³qzÓ$F6‹Ú‘2˜I‘g B •h,ZìÚKg¿Îé>Lbd¥bŠ|`Òpé!5$Ùb©˲îeÖÙ®=ÍÝN›N¡{žÑC"œ6‹$Þ,-¿y>uo¦­iËd¬´´>ƒ2ˆßPiR{~{ñüÕùÉÃh¶Mþq]È«܏X:Cõ£âÑcÿlð–±DʓMV¶ÆxÙÝ#ŒUu òéƒ`7Anm§bÄlÚ´i†º>é»G_°¿ïRéú¸¢mÛTpx4*%Q|ùé!ä³¼Ô¼f)›ڀ«˜:nÛ‡²ÚN¯»õqà ÈTølÇÎÝÆÛÆ/¡ûîendstream +endobj +182 0 obj +746 +endobj +183 0 obj<>>>>>endobj +184 0 obj<>stream +xڕV]oÓ0}ﯸÊ$MÚª[ 1Hƒx`¹ÉMkæÚÅv ´ÿ坮´Y˜èª&±ï÷9>ÙÏ^)ýe0»o¾êÏzý7ÈF0+ig|š%˜Î“ ÝLíÀ£Ù`“›x8IÆw6 ƒ·²@i™åJÛÑÎv0NFÎö¥«a.T~me.”Áæ70×,¿FkÀ,™ÍqÁ%ÔÜ.Á.Ô%— oEOH¬Ap‰ ÌÈÀ‡%K ¥BÕÆA©³ahÅX¦­‹°ç ¬´¨}†™É¸Â`Ö´nš$Tí® +²ó ׂžŠýÀÙCMÎÕnke64¦95ÊD“ÒÏïi` +7?‚(øñýÞFM“S÷ ädŸAÿÞ)µvñ7LÃqÿÀðЯ܊t —ZQ£†æ§ædÃD…ô¤ÕŠ ´ +&“I’$mLJ’Q@ W8<‡ô 8<ƒ,MýÝãÇWG-ëv“…ún—ÜP«£³®}f;öoVn÷ùû7 Ò ƞD‹+ÅÀ¿¨PшPtWêÍ]xI¿Ž;Q½ä£;·™Ì@B$9GB•ܱ)2tòeÎË=AGwA=‘åKˆrFµ…j +,Y%ln­‹V! AÄ´f7_ù·*mL\<˜Î^Î.¾¿}ýîžÞƒÊø=„œûÌ5²ëöVÓYwb©(µ\üoäÛ}¡Û#Gº9Liæº[æ* ^;õ†€«•.hâ8 ižÚ<¹:òñq+„ÔG€œ<äs´5¢cGYÉ|+·I²UÐ1'/L/ª@a"Ԛiº]¢á&iéù~“9|D[i Ÿ½ t¶z¹ ÙÔk*­UEéÑ>î•dW5T^J£°u‘3lÓ¨vdkðü'H…ÄpㆎL®ä†^-ÔçA]¨J´^ÑR¡jY3‚Šôïjå®|µÖjƒ@¿ ÍV°FM*°b2ï>>>>>endobj +187 0 obj<>stream +xÚíS=OÃ0Üó+ÞƒMì¸ù@Ê´Ù¥ seR‚š8¼º þ{ì&¥R‚øØI˺{绳_=¾ýD‚ÊÚ».¼‹,îC±ŔA (Vg7ëµy—¨ @½{Ü(X¨V£Lc}^¼XâsD *€<¢Üqó]]K܃^õ¥Ö—Aôæ'ԝÅb—¿üŠqb¥ˆhè†ô*«7…•Ùä`RÑ ²t‘ÍÀA| ,èμ\òtªË]­#M¥2CÔ8†éC#­1šÌ±j ‘$«l<#¤!íBvKõÅäÉx²!W›Í0ìØYg}֟ÖKݪïÒ?š¾•åsÕ(pNïZ…ÖeóDòýÖXºó5–b“˜&'­©2Ò:]ÁTmK¬ZÓ7%È*yœÉ?ïtùãc-œq¹Zú+ýó[ö…Æ],q³Â»÷>'Ó4ÿendstream +endobj +188 0 obj +344 +endobj +189 0 obj<>>>>>endobj +190 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 +191 0 obj +135 +endobj +192 0 obj<>>>/Annots 54 0 R>>endobj +193 0 obj<>stream +xÚ՛MsÛ6†ïþ<¶‡2Ä óQgzh’ÆjîŠB;êXbBIÉøßw]€Fr3ìÌØ‚W|,¾Ä¾ b™ïW¬éàkވ¾Ùì®^­®^\›†wÍê¶aÊ4ý ›Õ—ßVëÏ÷c3Ý6¯§ýqÜ¿¯þ»úsuÕµì7f¿}|kM/T«›]£[N¯ï›Ë>{û|×¼¸V cö¯ÙÃzx+ü5Ö<ŠÈ]ã~$|Œåf3}-ˆ+€Ã/Úê¿Ø£ç 'qÞöp⊷Štâ/®%É×±ç"VÇ6£dÙÁ±Ìj#)N¨¿¾ÀUßÞn7ëãvÚ[¨àˆŠt-iיV.Ú¹¨UŒu­DÅxI1âè„I8ö¤›‡ÃqÜe&r8älùˆ~*»¸§½ÿ1Î?¶ãO‹“¬5U_P\™Ô$ÅqWf€±S\÷ÖÙùœ€(N¨7Óæ´ƒiú8/FPJP7ú71‘ÃïžXv–µ]՛ÅvñõâÁdÕС=ò¼Éz˜20š‹zÊÇñvœÇýftAšv¨ÜkEaÒª>X,.Y¬Rú"/Z¬'jŠ%D +éõ¿n2—$ Wuö¢Ä,ŠËgÂbÖ}ÿ´—¥¤ºÁœqY…KS§uɜ=Gwà* ‡ÂDzü:αÃá֛­'0Š̋í3€W‘"ol€ïdîõ%«`.ÅEÁ(Å5ä~¨c\oaùø(&:t×'wÌ¡°ý½Þ¯ïF+·[ƒ˜¶Êµ*L÷N ·ºIéM¦“h²¢l2D„Â%S"…‰ôf;›ã4?<΋vòVûHqÞçÓæxšÝB[XûyúËQP_š.X<‚ÙHÃÐBEÑld—_ÀnÈuVøGq½;í>s(èl6•¤—*8,"Ô(x©&yŽÝ ”)ˆâ„z;îÇy]³Å–<²X7ˆ}Qk’çÀíÓ‡ÂDZ‡#Í(!ªÜ¼, ƌ[ ãi¹A$ïP®bE"ŠîmAŠ)Fyaµb±.[¸¡vW'‰ƒ åˆjz½Ìu‚S^¤8 +çíýt8¬ç'›iYííHVèìðzi*'.Õ®©{õ2[OfŸXð~ö¹°'­Æyç +1¯³—¥ë©)æN«O›b¼§¾ÓËl=‡Ú™l1 ˆâµ™§ýŠ&em‹G–ïhqM(fW8¸”¯’šQ¯²ùʬÎpöœ×Ó¨™ýŒ!‚ÙÛê3ÆåÒ"û~ÚÎãÒ"èU[ÏÖ+tf8§~˜:8¸˜êœ:O¯ +©.¢kp'D +¿¸mŽ·Ä,6n /´hÛ´­iã4£?ÜÀ)1ìB»&ƝßÀaL-(P=§{t0nšu)Šâ{·Þ-ë¡VØE‰ºÎY!ž…Du }ÐJÄK‰õv1 (ÎÒ' ¢þêS)UJ`¦±­æ’ ¡à0¾Y(7b¡{ϕP(Œ]¾ÓÞmîjy^â\+™ŸIl .š½Ø83ɶ¼ZÅdó$L¶Eq‚U—l%‰zìSáYôQ›ÊJÔ3_x1Ù< “-AQœ=ú0Ó%›,$›üÂXÐ J6©½[‹RºÇØ-¨„Caߎ_§/¸3ÕWøèMq6 ¬ÑlÊ[·('‘(ábÅ öìŽc¯ ςG­.+_*¦q(ÝbÅùsK¶Ž:e.%º¨­e“­ÓÞ­e)وcl77áP˜HŸÖóÖ>} ÛxY[º1•ŸJFë62qn£¼qËbª3-æ`”HÕåYAÍÂ:[³d™­¹÷mYL3Â`–ÅŒòô‘±²¬ðÜF¯ý~…À×ÑSÓÆû³*¤A´]>Ç fõð s‹«JŸ"-Í!¥‚U»×a)J/UL/‚`zÅŒ>Ëä’,¬«%K–Õ’{ŸVÅä" &WÌÁ(‘žQrqm®èäyn¼#÷¥ ímÝ$ fyN¯Ú{³Þ~°pŠÝò„4m3)æÌ‚v‚ÝãÒé3^áá¬æÃýzéa¯ýv/¶$ä?Wÿýž¡endstream +endobj +194 0 obj +1953 +endobj +195 0 obj<>>>/Annots 67 0 R>>endobj +196 0 obj<>stream +xÚ՗ÁŽ›0†ï<…í!Ä66¶¯›6=µÚnèÐ]¥ +¡%DUß¾c{L¤Äí)Éî +ivàƒù=ÿ~eŒPøe¤(íßk›=UÙ|i§¤Z& )• ÕÛ»ªþ¾kH·&‹n?4ûáð¾ú‘}¬2šS س‡—ODñœ’²¹&-1:/1ؑ•¥Ÿ]ÐoÈ|)cö~ŠÃ¹%œ 7|ʘ‘‹w‰À-a…8Ýoƒy„}©Ûí~caE‘+¨þ—ßð‡• ù8‡Çò¹ë²ñb”ˆ§$B+Ë\LQ˜G؇îõØÂÂÖöÛ[&\p#¥®¨ +êPµ´DмÀK‚.ͅWG]Ö&º´%Zs|:»úph\Ç ¿yûüw?Ic;ûÉc?I£ öŠ%-HÞræöh–“º€cÈ‘D:´TÒpã 7a^<˜Ýdiܔu¦ðÁh7©h˜×:a·ÀQSŽOì0‡¡Æ-Fð»3S‰N’å8¼}u’Taxë´Ù„f‹Q˜GØÝ™-%‘(ÜäõU¸ ’Hˆ0ÁuÚnHB»Å(Ì#ìž §†+¨›±Þ.ˆ ç¶ §ŽI9ÊvɄƒi$-º·Æ’àåÀÜáæö/ýÄT4¼]õÃe҆CvS ¼~œ^òÊÐb|÷A¤ ùI›¤ÓÄ¸m› +ó[ v®Ÿ˜¹›~búbqqS„Â:úK›/%~œØ³4¾^–*"€%è2Áa9«n=ü®û抏G¬¡}ٚà0¸ªïŽö+íò:Ž»©ðSåa}q/ÍÏ®®”'õùÓÁ #mÙõ­2òf-ÁŒ}€±zúÕ¸Æ3k.˜ßUߞWö{w½Ý{çuò¹ÞכÆzŸ<ïjçý +¦¸«k»EÁ¾fˆvrendstream +endobj +197 0 obj +700 +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<>1<>2<>4<>]>>>>endobj +xref +0 254 +0000000000 65535 f +0000000015 00000 n +0000000227 00000 n +0000001793 00000 n +0000001867 00000 n +0000001945 00000 n +0000002022 00000 n +0000002101 00000 n +0000002177 00000 n +0000002258 00000 n +0000002316 00000 n +0000002368 00000 n +0000002453 00000 n +0000002477 00000 n +0000002581 00000 n +0000002686 00000 n +0000002791 00000 n +0000002896 00000 n +0000003000 00000 n +0000003105 00000 n +0000003210 00000 n +0000003314 00000 n +0000003419 00000 n +0000003524 00000 n +0000003629 00000 n +0000003733 00000 n +0000003838 00000 n +0000003943 00000 n +0000004048 00000 n +0000004153 00000 n +0000004257 00000 n +0000004362 00000 n +0000004467 00000 n +0000004572 00000 n +0000004677 00000 n +0000004781 00000 n +0000004886 00000 n +0000004991 00000 n +0000005095 00000 n +0000005200 00000 n +0000005305 00000 n +0000005410 00000 n +0000005515 00000 n +0000005620 00000 n +0000005725 00000 n +0000005830 00000 n +0000005935 00000 n +0000006040 00000 n +0000006145 00000 n +0000006250 00000 n +0000006355 00000 n +0000006460 00000 n +0000006564 00000 n +0000006667 00000 n +0000006770 00000 n +0000007074 00000 n +0000007179 00000 n +0000007284 00000 n +0000007388 00000 n +0000007493 00000 n +0000007598 00000 n +0000007702 00000 n +0000007807 00000 n +0000007912 00000 n +0000008016 00000 n +0000008121 00000 n +0000008226 00000 n +0000008330 00000 n +0000008431 00000 n +0000008463 00000 n +0000008495 00000 n +0000009190 00000 n +0000009238 00000 n +0000009286 00000 n +0000009334 00000 n +0000009382 00000 n +0000009430 00000 n +0000009478 00000 n +0000009526 00000 n +0000009574 00000 n +0000009622 00000 n +0000009670 00000 n +0000009718 00000 n +0000009766 00000 n +0000009814 00000 n +0000009862 00000 n +0000009910 00000 n +0000009958 00000 n +0000010006 00000 n +0000010054 00000 n +0000010102 00000 n +0000010150 00000 n +0000010198 00000 n +0000010246 00000 n +0000010294 00000 n +0000010342 00000 n +0000010390 00000 n +0000010438 00000 n +0000010486 00000 n +0000010534 00000 n +0000010582 00000 n +0000010631 00000 n +0000010680 00000 n +0000010729 00000 n +0000010778 00000 n +0000010827 00000 n +0000010876 00000 n +0000010925 00000 n +0000010974 00000 n +0000011023 00000 n +0000011072 00000 n +0000011121 00000 n +0000011170 00000 n +0000011219 00000 n +0000011268 00000 n +0000011317 00000 n +0000011366 00000 n +0000011415 00000 n +0000011464 00000 n +0000011513 00000 n +0000011562 00000 n +0000011611 00000 n +0000011660 00000 n +0000011709 00000 n +0000011758 00000 n +0000011807 00000 n +0000012068 00000 n +0000012220 00000 n +0000018579 00000 n +0000018601 00000 n +0000018696 00000 n +0000018798 00000 n +0000018818 00000 n +0000018972 00000 n +0000019997 00000 n +0000020018 00000 n +0000020131 00000 n +0000020319 00000 n +0000020340 00000 n +0000020480 00000 n +0000021244 00000 n +0000021265 00000 n +0000021378 00000 n +0000021571 00000 n +0000021592 00000 n +0000021723 00000 n +0000022338 00000 n +0000022359 00000 n +0000022472 00000 n +0000022661 00000 n +0000022682 00000 n +0000022813 00000 n +0000023754 00000 n +0000023775 00000 n +0000023906 00000 n +0000024191 00000 n +0000024212 00000 n +0000024352 00000 n +0000025260 00000 n +0000025281 00000 n +0000025412 00000 n +0000025768 00000 n +0000025789 00000 n +0000025929 00000 n +0000026573 00000 n +0000026594 00000 n +0000026725 00000 n +0000026990 00000 n +0000027011 00000 n +0000027151 00000 n +0000028276 00000 n +0000028298 00000 n +0000028438 00000 n +0000029260 00000 n +0000029281 00000 n +0000029421 00000 n +0000030339 00000 n +0000030360 00000 n +0000030500 00000 n +0000031143 00000 n +0000031164 00000 n +0000031304 00000 n +0000032121 00000 n +0000032142 00000 n +0000032282 00000 n +0000033210 00000 n +0000033231 00000 n +0000033371 00000 n +0000033786 00000 n +0000033807 00000 n +0000033920 00000 n +0000034126 00000 n +0000034147 00000 n +0000034301 00000 n +0000036325 00000 n +0000036347 00000 n +0000036501 00000 n +0000037272 00000 n +0000037293 00000 n +0000037348 00000 n +0000037453 00000 n +0000037597 00000 n +0000037703 00000 n +0000037823 00000 n +0000037932 00000 n +0000038081 00000 n +0000038191 00000 n +0000038298 00000 n +0000038452 00000 n +0000038563 00000 n +0000038680 00000 n +0000038796 00000 n +0000038960 00000 n +0000039066 00000 n +0000039185 00000 n +0000039300 00000 n +0000039404 00000 n +0000039560 00000 n +0000039669 00000 n +0000039784 00000 n +0000039896 00000 n +0000039995 00000 n +0000040142 00000 n +0000040239 00000 n +0000040339 00000 n +0000040497 00000 n +0000040637 00000 n +0000040737 00000 n +0000040844 00000 n +0000040994 00000 n +0000041094 00000 n +0000041201 00000 n +0000041349 00000 n +0000041449 00000 n +0000041556 00000 n +0000041706 00000 n +0000041806 00000 n +0000041913 00000 n +0000042059 00000 n +0000042159 00000 n +0000042266 00000 n +0000042417 00000 n +0000042517 00000 n +0000042624 00000 n +0000042772 00000 n +0000042872 00000 n +0000042979 00000 n +0000043129 00000 n +0000043229 00000 n +0000043336 00000 n +0000043468 00000 n +0000043575 00000 n +0000043674 00000 n +0000043792 00000 n +trailer +<> +startxref +44019 +%%EOF diff --git a/doc/cmp.shtml b/doc/cmp.shtml new file mode 100644 index 0000000000..898b3f8c9d --- /dev/null +++ b/doc/cmp.shtml @@ -0,0 +1,595 @@ + + + + + + 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.1 software. + + + +

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

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.1.0
    +
    +
+ +Beta-test releases are indentified by appending the letter B followed by +the build number: + +
    +
    +major.minor.patchbbuild
    +1.1.0b1
    +
    +
+ +A CVS snapshot is generated for every beta and final release and uses +the version number preceded by the letter "v" and with the decimal +points replaced by underscores: + +
    +
    +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.1.0b1    First beta release
    +1.1.0b2    Second beta release
    +1.1.0      First production release
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +1.1.1b1    First beta of 1.1.1
    +1.1.1      Production release of 1.1.1
    +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.1. 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. + + + +

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 +".cxx" 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$" tag: + +
    +
    +/*
    + * "$Id$"
    + *
    + *   Description of file contents.
    + *
    + *   Copyright 1997-2000 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:
    + *
    + *   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$" 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$".
    + */
    +
    +
+ +

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.1 */
    +do_this(float x) /* I - Power value (0.0 <= x <= 1.1) */
    +{
    +  ...
    +  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..4d01504f46 --- /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 { text-align: left } 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..c13291294d --- /dev/null +++ b/doc/documentation.html @@ -0,0 +1,77 @@ + + + Documentation - Common UNIX Printing System + + + Easy Software Products Home Page + Do Administration Tasks + Manage Printer Classes Status + On-Line Help + Manage Jobs + Manage Printers + Download the Current CUPS Software + + + + +
+ +
+ +

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 ) + +
  • Software Programmers Manual ( + HTML | + PDF ) + +
  • Configuration Management Plan ( + HTML | + PDF ) + +
  • CUPS Implementation of IPP ( + HTML | + PDF ) + +
  • Interface Design Description ( + HTML | + PDF ) + +
  • Software Design Description ( + HTML | + PDF ) + +
  • Software Version Description ( + HTML | + PDF ) + +
  • Software Security Report ( + HTML | + PDF ) + +
+ +
+ +

The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software +Products. CUPS is copyright 1997-2000 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/glossary.shtml b/doc/glossary.shtml new file mode 100644 index 0000000000..f13ac3d37f --- /dev/null +++ b/doc/glossary.shtml @@ -0,0 +1,76 @@ +

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/idd.html b/doc/idd.html new file mode 100644 index 0000000000..fd2da2b9d2 --- /dev/null +++ b/doc/idd.html @@ -0,0 +1,805 @@ + + + +CUPS Interface Design Description + + + + + + + +

+

CUPS Interface Design Description


+CUPS-IDD-1.1
+Easy Software Products
+Copyright 1997-2000, 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.1.

+

1.2 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.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

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

+
    +
  • Adobe PostScript Printer Description File Format Specification, + Version 4.3.
  • +
  • Adobe PostScript Language Reference, Third Edition.
  • +
  • IPP: Job and Printer Set Operations
  • +
  • IPP/1.1: Encoding and Transport
  • +
  • IPP/1.1: Implementers Guide
  • +
  • IPP/1.1: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
  • RFC 2567, Design Goals for an Internet Printing Protocol
  • +
  • RFC 2568, Rationale for the Structure of the Model and Protocol + for the Internet Printing Protocol
  • +
  • RFC 2569, Mapping between LPD and IPP Protocols
  • +
  • RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1
  • +
  • RFC 2617, HTTP Authentication: Basic and Digest Access + Authentication
  • +
+

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

+

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>
Surrounds a class definition.
<DefaultClass name> +
</Class>
Surrounds a class definition for the default +destination.
AcceptingSpecifies whether the class is accepting new +jobs. May be the names "Yes" or "No".
InfoA textual description of the class.
LocationA textual location of the class.
MoreInfoA URL pointing to additional information on +the class.
PrinterSpecifies a printer that is a member of the +class.
+
+

+

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
AccessLoglogs/access_logSpecifies the +location of the access log file.
Allow-Allows connections from the specified +host, network, or domain.
AuthClass-Specifies what level of +authentication is required; may be either "User", "System", or "Group".
AuthTypeNoneSpecifies the type of +authentication to perform; may be either "None" or "Basic".
BrowseAddress255.255.255.255Specifies a +broadcast address to send CUPS browsing packets to.
BrowseInterval30Specifies the number of +seconds between browsing updates.
BrowsePort631Specifies the UDP port number to +use for browse packets.
BrowseTimeout300Specifies the number of +seconds to wait until remote destinations are removed from the local +destination list.
BrowsingOnSpecifies whether or not printer +and class browsing is enabled; can be "On" or "Off".
DefaultCharsetiso-8859-1Specifies the default +character set.
DefaultLanguagecurrent localeSpecifies the +default language.
Deny-Refuses connections from the specified +host, network, or domain.
DocumentRoot/usr/share/cups/docSpecifies the +document data root directory.
ErrorLoglogs/error_logSpecifies the error log +file location.
Grouproot, sys, systemSpecifies the group +name or ID that is used when running external programs.
HostNameLookupsOffSpecifies whether or not to +perform reverse IP address lookups to get the actual hostname; may be +"On" or "Off". Hostname lookups can significantly degrade the +performance of the CUPS server if one or more DNS servers is not +functioning properly.
ImplicitClassesOnSpecifies whether or not to +automatically create printer classes when more than one printer or +class of the same name is detected on the network; may be "On" or +"Off".
KeepAliveOnSpecifies whether or not to use +the HTTP Keep-Alive feature; may be "On" or "Off".
KeepAliveTimeout30Specifies the amount of +time to keep the HTTP connection alive before closing it.
<Location path> +
</Location>
-Specifies a location to restrict +access to.
LogLevelinfoControls the amount of +information that is logged in the error log file. Can be one of +"debug", "info", "warn", "error", or "none", in decreasing order or +verbosity.
MaxClients100Specifies the maximum number of +simultaneous active clients. This value is internally limited to 1/3 +of the total number of availabel file descriptors.
MaxLogSize0Specifies the maximum size of the +access, error, and page log files in bytes. If set to 0 then no +maximum size is set. Log files are rotated automatically when this +size is exceeded.
MaxRequestSize0Specifies the maximum size of +HTTP requests in bytes. If set to 0 then there is no maximum.
OrderAllow,DenySpecifies the order of Allow +and Deny directive processing; can be "Deny,Allow" to implicitly deny +hosts unless they are allowed by an Allow line, or "Allow,Deny" to +implicitly allow hosts unless they are denied by a Deny line.
PageLoglogs/page_logSpecifies the location of +the page log file.
Port631Specifies a port number to listen to +for HTTP connections.
RIPCache8mSpecifies the size of the memory +cache in bytes that is used by RIP filters.
ServerAdminroot@ServerNameSpecifies the +person to contact with problems.
ServerNamehostnameSpecifies the hostname that +is supplied to HTTP clients. This is also used to determine the +default CUPS server for the CUPS IPP client applications.
ServerRoot/var/cupsSpecifies the root +directory for server data files.
SystemGrouproot, sys, systemSpecifies the +group name used for System class authentication.
TempDir/var/tmpSpecifies the temporary +directory to use.
Timeout300The timeout in seconds before +client connections are closed in the middle of a request.
UserlpSpecifies the user that is used when +running external programs.
+
+

+

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
AcceptingSpecifies whether the printer is accepting +new jobs. May be the names "Yes" or "No".
<DefaultPrinter name> +
</Printer>
Surrounds the printer definition for a default +destination.
DeviceURISpecifies the device-uri attribute for the +printer.
InfoA textual description of the printer.
LocationA textual location of the printer.
MoreInfoA URL pointing to additional information on +the printer.
<Printer name> +
</Printer>
Surrounds the printer definition.
StateSpecifies the initial state of the printer; can +be "Idle" or "Stopped".
+
+

+

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. The URI method name is "socket".

+

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 Internet Printing Protocol

+

The Internet Printing Protocol is described by the following RFCs:

+ +

The URI method name for IPP is "ipp".

+

CUPS defines the following extension operations to IPP.

+

4.6.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.6.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.6.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.6.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.6.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.6.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.6.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.6.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.6.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.6.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.7 Line Printer Daemon Protocol

+

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

+

The URI method name for LPD is "lpd".

+

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

+

The URI method name for SMB is "smb".

+

5 5 - Directories

+
+
/usr/bin
+
The cancel, lp, lpq, +lpr, lprm, and lpstat commands reside +here.
+
/usr/sbin
+
The accept, cupsd, lpadmin, +lpc, and reject commands reside 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..bcbf5c1c12 --- /dev/null +++ b/doc/idd.pdf @@ -0,0 +1,868 @@ +%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[11 0 R +13 0 R +15 0 R +]endobj +17 0 obj<>endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj[18 0 R +20 0 R +]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[23 0 R +25 0 R +27 0 R +29 0 R +31 0 R +33 0 R +35 0 R +37 0 R +39 0 R +]endobj +41 0 obj<>endobj +42 0 obj<>endobj +43 0 obj<>endobj +44 0 obj<>endobj +45 0 obj[42 0 R +44 0 R +]endobj +46 0 obj<>endobj +47 0 obj<>endobj +48 0 obj[47 0 R +]endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj[50 0 R +]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[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 +]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<>stream +xÚìÏsë8rÇIŠºÌ‰öŒî´üt§çyšÝ­ÚJñÙfvçÖ$ÁÊ!•S*Ç6•üÿ±~X"H€èn$è5¦jêÙE|ˆÆ·@ƒúÇOßòýÛßò?=å¿ýžÿçÿô,~*ÅOÿÈÛÿù×?þøÛï¿ÿºÏÿü—_Ÿò§§§·kýñõ¥ù÷¯|­ÿöœþº?•ßNå÷SùË©¼œÊ¿žÊ¿üÇ×?òÿýŸÿû¯¯ÿ–ÿíÛ׿ç‡oß¾>ÃKþ=ÿãõ§öcøä²+âõi»Ý>ÜËÛ?¶ß_—Î%^¶wY¤*w÷¯ËäOj¤Üöû¸ē‰é½Ü?–KáÂC]о/ëå!"—x[ÎõœE¼r˜ë‰KåÒ!˜¾rÛg޹^òȾü\ÆÕÊÏ3s=GžJRÎÉõ-òVâÃl\ŽuЄõV¾ÌÂ%²( + ‚B¹ü29×$X,0X –€Åƒ %ƒ/° ¬(ÚMÄåÝoÙ9h6×ÄXo`å\ûhò’LÀõ#𡬼sÕÑ,åÏ\M6A!|…gi,A +Ú Ñ ê£s5Ѭåà‹+›— 9Ä`™ãÅ`ž‹,öD.1?V{àÊàŠRç\uD98æY\‰c®}HÙ8媣`Jé++D91WT蚐°ŒÒË TÔ  LÔ‹Š4ðZåªBÃ2t,OãQ ÔxŒsÆq‰±FãzX¢Æ#F,Ï%£FL×]w÷Ûí—×cy>|ðÛa0IwÅ÷_†ƒüxÂ[‡ÿîŠG’þÅ˃ŸßÝuoœ*=[ í,¸ö~ºªÛk[ça=xì.Bú±àæØ\ìPƒ–.Î$[q¹¸¡==·aMJ&³»XéԜ.K™\¬@ž› É貘ÇUùÑv‡]¶cqeSÙà՛eN¤ܯjؤ½s’  ®|²¡ÅϼJé\Í Xd°˜ÎEùØÍÉÜZ9ƹfÂ"‚­¨\Õ FÈ1ŒȕυEÛи'’ –Y¹0p7ñú¥uZj+Cg‘¼c,Òé« …«rÎX•½ÅÍÁ‘jÄ¥{.B J<—°ÒlKÃ7D=Ì:¸ÎåÛÁÉ %i=•œkˆàBf½ .Ú`Ø`¹Š¹2O”,Á W­Ç’ó ìÍПR4q‡ãÚa…„–¤8®´&1Š«žÙ#3ì€á«aÚz/8 [c¸²0Dƒ¢õ ‚«æfóuXiæ*B J‡íÌ\Y OjOjäªÃê.d‡%F®"°îBú°ÒĕÖ]È'½1p5Á¸dZ“RW\wá¢ÄÄÀ•6ºÐRVŽr‰» 7æw£\u€Ý…[FJG¹*OŠ…²¢d”+ (2$*ÇVå'ÆB ÃRåÓ©¹Z’ Wå“s! q5ÂÀÚÛ=W¢È£­ÔrAˆ"v@;-W¨jàLi­ã¡ªnè¯t\5-4”=Ùí§ž±¿ÿ.Ï´’T¹Æúù=¾aÀ +¢6(®–KH·Kh%ºÖRÕÓbQ®•–ër›®Îa‡Àà ¯Çé¹ £^ >ÜÌіœáµCrí´\MçùÖ 1£$UsÑys¥Z®³í%·NH)}¢æÊ‰Îkœ+ÑsÝ´BPf=ègŒàp‡åz7.×MÛk¼b”¾Tq5ÔÊÀµÑrÝD° ¬•T؇ô¹WŠçZ鹊÷G”Q&ß V<זByW¤çª/ŸÕPÌ1PRWF4C#×NËu¾×úü+ü’QØV +.A5C#WªçڟòáªÕr[¬àª©fhäŠõ\盽§5Rì•K,×êZ[Éu6Ž;êÊ12BªWNZ,×:{—'%WG¤(³ÔgO@• ž«x j®Š5K5†ˆëWC6Ãq®ZÂp ÖbI…Ó5 ÊFÒâ¹Ä»Y¨¹®&EZ,ip-â\9%pžê¹*֚Nè(; +\n£á¬5;c+\ŒôÅq®æ" +®K‰kvª‰@“¤¥pµ¥×qgéB™ÐdcMãº(½Ž«àôWòD@“ë¢ô:®Œ3¾êÙwCÅuQz WÍÛÃÈ0’ ¤h#!r]”^ÃUðûMÏ%s Æð2r•^Õñ6g +ÌÃ’lì¨\g¥Ws5Ì]Œ +㘁´¶ÑR¹ÎJ¯æ½ØER2WÁ^f®“Ò«¹rfæŽÀ8f DQ)ëd݅~^¹e¢IàkSYŽ­\§Öç*®³Ý Fȑ#š ”(ªT?º²k ±ÌukDŸ+?krN7Ä="àVÌµë>š>h¸Þ;а›‚]†Yw¹k6+IlºŠšô¸ Wuáiè†X!dr¸Ñ˜ÄjøCýsȵèÝJ´§•¸rŽlH[âã‹:\…’K\[°'¢@Ø¢C­I¤€]Ÿ«VrU×Ê=öEèà£ÃDïû¯´ùÖṌŸêsí¯#èùVž«áxåÛ-â;^WÈ\OÌɱonn0¾d=äª\ÝT”‚lˆ{ó€¼0ÚT¹WWojò$ ð\{–l lbÕ¹.¶*qeÝKž„‰×ñÒáÊY²Ñ˜×Ó{Šyq—KΈÚ{ÈhzªX¯üPy8Å:F—« »òúh9ÔNþnï5ùÒ*¹Ä€+“,¯ñª è¨Wo'ÍéŧñýGH©\SßËy°†ÇeŽæãvQ°2Ÿ,’+çEQÁse¼(*t.a#‡s5–r*W͍çª>š^¸ +vt6מ͕4™¿peM/\œ¥ùp‰'óg®úÃÉ<–k2ߝÎ-‡͋ó·•Ü:\[æ»uîªßFwÒ²ßmµwpœOm›.Ò,²Î-ï\·u›þà,•\×FÍÕI¿\¹r¶ûRãkT§×ćk¥äjÔûËÛ}©4fÜkbÄኔ\¹z߁¿h£¶W]nj¯‰;×NÁU UPn9Ár­4áËNŕr¸RW6|ŒŽ¹Î«Ëë51áp%C®wшﲫÝÊ-§h®š+Vqõó¡¸g¯r~ô'/ÙÅlp\ëQ®Ó¿^òHjÁZv,¥Šk£tEr<Џ¨ëdÞ7ÛnlÌ\—᯻?"éx@·‰+×à¢Zr—Ûj{‡àꤥÈ]|Ëíé71âp .’7.y<€ +£®[‘"K~­lâŽÃÕ¿(—óM +-áðì8—Ðpz®”ÃÕ¿¨7RNf™*Œj1\·Ùÿj®˜ÃÕ»¨ðTà¹b\Šã|f.ÅEußÁnßÊ#`ÂÃĞk¨Šã|f.ÝÀT5_ŽÜp ×^­óŠã|®áE…ÒÁ&ŒJ[=Ì®9·r‡Çù\Ër¥#Bq­Q\µÚ՚8JqœÁ5¼HËU;â*”ñÆË- é5qxœÁ5¼(S:"×Ã%¢"ÎSÇù0\ƒ‹´\?Œê´áò;ô¼RqœÃ5¸¨[ývGסµœm”MçÃp .Òr?ŒjÕ£YU4ñ"Ú4®þE\-š+Uý6.5MìçCqõ/Òr¹ê^,ÕMìçCqõ/Òríùáa«68Íòþ ‰ýã|(®þEY/Mõʕ;ãŠK W'T•šØ;·ãê]ÄçJ\ñ®óۋ_¾,{lÔMìçÃqõ.Ê;Š-qen¸:ù‡Ýxã¼ì‘ª›Ø;·ãê]4ˆ£*,WÚâæ)­Š«ó~(EO¢Må’/Ú÷#¢âÂùåªÇ¸äã|H.ÅÀn÷X®µW£‹ç¯AeNä’/ªúC%;s Ï\BsŠCqœÉ%_T÷$[DX®W;Ê.é"Ñ Í« ¸—|Q&°üÂeÎ=Üy䒎óa¹ä‹ +E2þW=/WÁá’.ªn»Ê·EÞÙ¹j—t‘è¶²¾Æ6ÓJ\‚Ã%_”ßö¿ž#W铫{œÍ%_T ö+Càª8\òE½H0?qÙL—Q\Ù8WÃá’/’gÆé>®Îq>ès¥”ºór=ŸÞa?bšK©;3×Cÿøšü²¡ÎæuÕ»ꝪHqPJÛ:k®|¾!çéw·§†u\y1Ô׏áŒF~™WsÛìø9QeäÚÉÔ—Pì(É/4¬®KüuòÈȵ™‚ TSë¼;Àz齺 ®u+ M?\™j« ºã “Òdúu\©l)^¸š÷§»nÝî«ko»õʺ ®Dºµ®êºQ(¾unڑÀ[v…².Ÿ«öÉUtv¬÷7ïÒqY·äsM]Õ2¿ú®òöNå“+ª›v^Ȭ©K㊯ۧoƒ8ñƕu—áòžÒߌ§©KãJ®£0qÙÄóҟá¦×VËIÚªº$®Õõq¼=™t®êöÓ5ä$mU]WÚ}tk;.CúáõÏÍÝ[ÙtĪ윑Ò×%qÏ]ÓÆ+W¢ûѧ“T<¶ÔçÊ/ƒô8„wÞ¸2]:ÎeO¹éÀd#©;x®ýåóŽŸ|ðÆuŽš¸1‘†‘¶.‰«¸ÈÐÑÒKo\—½Îûƒ:À:eR¼Ë¹¶.‰ nÙ¯qëë¢Z{þ⇬ã‹õu•\ÃÄÎEu¯G÷叫“Òkmñîm®¾X_—ÂU_ `ü`;®±}½n=é½ÄÕ0‹V[—ÂÕ\~<ºeK®±}ØByŽCš—ƺ.]_ˆ¾ç²Ú_ÚÌÒ|Õ¢¯Kàj/Žùô[\½,Ú¸ôdЍKá:;æ“[öÉÕyіL¡ú’9]] +×Ù1×'ï“ëý ì —J•l:ZÇuvÌõ©¾—1ïë9Sš\ùPÔuñ~ùäËãÿc—‹|¶—‡á¤¦ÒLrTu \ÕÉOnÙ?×­µ«^(u@Õ%póÉ-OÁõ. +‰vЌÕ%póÉ-[raß-Z‹ÁX]—x÷b멸n‰×f®^]×Ù1ŸEr”Ë&ûø*™ìе\cu)\o&˜4·õS/\²{ãb§®.…ëM2âúì-¹JÜú¡k¬.…ëØÓUt}Q7®D²­x”KW—Âçð±‰ËæÜM.ý9Õù±º®ê|²&±çڍO¿6ÝyÈJË5V—ÂUߜº7®ªÛŸûÞmz«Kájn³Q.›sˆçkãï·M­–k¬®!ž—Þ¶%ä]A ®qö¶ ©Ÿ,ŽÕ¥puÞ ë«™«õ¹F꒸r—Õ¹ìf¤jŸk¤.ƒ«´çZãÒmú¡ÿ VÑ×%qƒßxàjô +3àj¸ëQ2\ŸÊ(—Õû7䵘_ÚQ.}]—îý¬n¹:}l \Úº$®úêÓǹ¬²Þè!Ón”ØÔµ*–ïí¹Ê×ëMóU|–ïY +¶X¾ë“kz.ó떗ÉUüÓr•‹ä2/pÉe3aþ䚞Ëjb¹h®õ"¹Ä?-WºH.ólõA¹’ere0ðµü>ŽO®¸ö0ðÅ}Ïn‘\ðA¹ª Z~¯Ù\Åô²×å÷ÐÍULMÞá¾70¸@ªrÃ\ e’ºÒò{9ç*Š+[\Àa +%°ß{ZÀ‘›ì ù=Å¡­´e&=@~¯thG„â‚¥Âèo‘ßoXÀQã¸÷}ô•±mç˜Á8lc®Á9æ½Qæ#/Á9°Üè–ã‚s`™±Åš3‡}€²×ÀXcV@éK`3Ëڬހò9°ÊÜX@=€ÀXa6.@l`3°½9êT˜ËÍ"8á Kèmœ£ Jè„m®gƒú¡€S˜ „A:àª%ô¢©€ìڐ„>G˜ ‡bH}fv_ï\bAB/0Ò -Vè׋‘Ã]‡+_Ž V˜Ȑ+ A,0 +-V裥ÈaÜ媗#ˆ(Â-ôDˆ *âƒ-ôéBäpÝåB} Â(»‚-ôÇ¥€VÏP„#C̾:\ÕB")£œ· Å }ºÙHd.„Ð'‹TæB,Ýċu+_†pd8üƒ"âȇxà B8j¤—Â!Gl#´A `1Û¨«>BðÌØå +h)‚¸xí\Åú,(ÖCéÑg­¡% ÇÜ ýŽhIÂ1ó3?ú•‚+~€áï€d¼s°=z @KŽy>r’s˜y€Õø©bå™a÷H*:sˆH؇–(30Ê&ÐúyÖ9eˆιÈQDs‘ƒ²Ôā9£Ò7”AОQéI+Ò@½t>¥Ï)Mª’ζÚ&HšÔ¡9›!"li¥åڇkˆ´åhél¨vc! »ô™ ±¢g83âžö¼nų¢ †®@žâÌcˆñqCË`3Ĉ9qx@Ë`iˆf(Í4€ó`¦Ÿ¬Tԇ -g€M>kΩj-k€MœdY“½´¬6± +ÈcX]>±rz‹€5D'VFÔ +œéöÔ1GNÀY™8樼A:©ÔgB©œÇ Üϙ.H,8ޏÃtºc wàÊêd†kÍÁ…Tú‰:,c=càÔ4Æ €?R§é°ŒÖÛNÓaә_‚& :C¢Åqí±`»0ºk…äªé0‘qƒph­ ±÷UKó„ªY.´v†èuâ,øV­!zÕzìÓÝ ¹ð†èQ:j ›ÖÖãrfWŠØ ¬OKüñÍPË%¢¹-±±’.h­ ѓ&æV>¬­'BõÊXZ?Þ¹±´°öõ^†˜È,e \<1÷3–½í#×½{&ܸ¥rU¤s©ÍJÉ\"š LdöܹK0‘;¸)82‡i\o\´;¼•Ÿ'–‘P¬.t¬Â^¿¹1p1_uFÃÒÇàd}¡ãNSbé¥ +\EiW°/)áøf08Ô&[õ cœFwžÿf<[l2êR6W›qÀúßtŽ*OôÛø\‹+Š¿S;‹añcq€‰‹ÙaQt_zî¬ñ¹‘‘«ˆ¸ÿ¥ó/9k·6\"â—{”56¼OßYqYtØqœ=šÌñ…Ie˜>˜¹l:ìŒöªÿ짌ý¹K.ê4Li¯ƒ~/ÛÌæqµ¶\Mä¦ÜÝo·Û/¯oåe»}È,?mcÍå¢ÃœSþ#†KȵqÀe'‰³tŽ+¼Û9á +®ÃÌK_8.±´îBrvm¦(ˆ=$W›…ÄupÇU/«»Ð\¬•O_ºäj‚áÚ´.¹‚ÑzÜöžKdKÑxw gÑ q!Øý^ +—XŒÒ¸°DôÖ!‰kvKÄgиš…X!•kæø—°MäšÕ)¹/T®9½3eû‰Ê5c`OJš#sÍ6Ähi/t®™†1±ŒÁ5Ï#îí2¸fbÔ,%=pÍ`sM®ôT9×ÄÚÁÈdr‰<\)´ášRY©Ã\®éÀx™dl.FÚÏ$ŽËšk¢Éóā×þ9椰áòoŠü,M+.ß`ɧv\~UÑ&Yؒ˧ƒ¶Ê¶åòf—ŒoÍEΡö41qÏåcÚb™®î†Ë½,ڟ›pÂÕ +·¶øhß"7\o¶è®Ë’CW+Âé,—\ŽºìþІÆÕŠ'küâª-.¹ø©ÕªGw-qËe‘^Hݞ“‹Kæ–ʇìþ‹ë6øà"æÅÇ[ï¹ðÃõV^qÙññýw/·÷Æuê5ƒAÞm_}ÝÛ'ש۞¶wê~z|õy_ß\çŽ;žpØ>ÜËývûøúêý–“pÍPàÿÿÿârõä +äÿÿMK‚0„÷œâ_jbk[^v©‚ ;„zk%mÕp{©‰‰«Ifæ›9‰`áÀˆÒGr|Ñm粆brÒôM+!“V “—Ö¨Ù)=mÅce# Ô³”q¢!f?Y†(¦¾ˆhŒ9 –¬kœ7vZ÷îÝ ¥Ñݳuö[ŒBœüíèy1j¸; œ§ˆBvpG¨¼i¡’Vš—ì<š‹à|r6ñXendstream +endobj +142 0 obj +6288 +endobj +143 0 obj<>>>endobj +144 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +145 0 obj +31 +endobj +146 0 obj<>>>>>endobj +147 0 obj<>stream +xÚ­SMSÂ0½÷Wìp‚©¤ÔÞÐá¢(ÅñÀ%“nKœ6Á¤‚øëÝ´ øqat:ӏ¼}oß¾4σ] zt#…w{§W:§„D½â¤É`&ô +[ñS…²^¶#æî3˜$¨J™JÁK©U]c»Ò ò+©x)-HU¢I¹@HÐÊL¹‡0r嘐hñR¬Œ^KB-¹Ì1”îjSðҞ@Öòì`«Ä‘2à ןº²nmPhµvö´²®Ê%ÂPµ›ßLajȒT̶¶ÄÍÆp>5-x@c-šÑÿ@ØñûuŒö¾o×hÖ7ÿ‘j“q%ßh|¢èÊzªó\oœ_‹¢šê¼n&v͂>úè·¢|uC[Ú>ÜTñérŸÙo,…{LÑ h¢v‰:q3+ž×/nøã4BÒ¿þMãŒ4FÒPnÚÈ#¹ĽÎ5ývf[CýÔ®‰};1a¿ãHÙ­ºïqìÝyïÎtúxendstream +endobj +148 0 obj +384 +endobj +149 0 obj<>>>>>endobj +150 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS045×3S072PIÑp VðÌ+I-JKLNUpI-ÎLÏQÉE™%™ùyš!Y\º-ºP=F 13 ˜o¨œœ_ +u á +ä, ëendstream +endobj +151 0 obj +113 +endobj +152 0 obj<>>>>>endobj +153 0 obj<>stream +xÚ­–Moâ0†ïüŠ9v%HI r£PZVE͒´§½g^%6k;jù÷µ>ʖJZqçyçãQþ6|h›½:!Тq“4.'×´!É̝°×…$½`ŽJäՏä;â÷ª#­Ð÷wÈóaôÅ0´,k¢™àÕñ.øþöxzŽ™¬2‘çâ…ñeõ`úþA` +äN5…ÅôÊ\ڝT`º}Ğý;{p¬|aZ£YÔò=PéÏز”•ÞŒp²Dˆ('ü˜o÷;UžŸÂ§ãñ;x¼Q ˜r2#aŒŠ-¹ý¢’­µ©#gVÂ{݉ˆL¿‰0L ƙÒ&!•Í¥$ùüãvôo =šBGR,%) +k‚³£Žç§Ð1ÒR2½1æ] ©Ïà&Ñ)n‚ê\‹ÄOŸôïIáWÚö<>}6TëíÛÍo«œnÛëW3À£^¡Ü±úÏ悷ކX à;'x˜Š…1ŒP:vÉï0;]ﳃ Ë&BDC¼FÊ2FÝ|7÷Åèz¯V??¾,Ͳ8¬Å&$+&S¸M™«ÇŸFÑ~Šžî“ŠQÃã«å¤êò.oo9©íŽ'’pU{ö¬i±ÎÝv´F½+YŠçqf"ÅÜcA¸f´^róÉÈüì]7áq>>>>>endobj +156 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS045×3S072PIÑp VðÌ+I-JKLNUpI-ÎLÏQÉE™%™ùyš!Y\º-ºP=& 1#C ˜o¤”š–Z”š—œZ ’r á +äÍÃ"ïendstream +endobj +157 0 obj +118 +endobj +158 0 obj<>>>>>endobj +159 0 obj<>stream +xڝVßoÚ0~ç¯8±*•” +t{bU+!í§Jߐ&ã\Àkâd¶³Òýõ;Û!„´j·¨/nüÝwçïΟùÕ aD!Ì"Og½«ÞÅíD#X%´3M`ư”•d©_$Œ£>[ýtØpæ±ÃiD„p½cŠq‚¸é?0¬ðÑ4p쫯ñšð‰ÅCŒ‰ 2VBnaƒæQÂ|¸æ¢É ±ÜKÁó¸Å%x¦ÐV@yñ¯S² c(µ¥¶ÑË»¯  q1ƒ,³ ÅûbHrå0-æÆw®Zà¹ÔB ye&‡èr +)ÛO­Ì‹»ëå îwBasØážÅÈEF²ûrôWD"”6‡ +…nvø.í÷VâS™×ƒÑ~4²µŽöI²>;¯…ÔHÅÄ­ÏÕ­ö=ϑÉrÏÆc2 +æ~<"øÄä¶d[ü‡ÉHГ¡°õВ•©i͎=#-Ó¹¹tj’Ґ¡ÖÄ£½2ÌÔÌo Èæ +EY÷‡9ÑFÙeŸ—…þÑ·‡vMQ¹4.Y³h]PáDÂ`TQ(ûçÕ2Q´DÃõY+ýËÃe'ƒ†1ËÖ㍁ªHšúyq3&b”ƤŸ³=ÉéB4æý šÓx©ŧO h@¶Rü!èo––DGò½÷äU#£9£.dMgpÚéA©‡Ls!Nã¼d’áü¿"„·óùåÕ0ìu w ›t »ì6í6ëÖ±oWÛÝQÊÐi9<ßÕÑ­Åè’sÄØ¿…cjZMˤyü.Ù) +ÇØ› «lôÜ"_4mëj’£+—EÌ Æµm;z–ØûlÿméN¿æÈcø¼ü|ó†_ß»³LÚy ðžL†*Ȝ귓DJĶTÌúï1í¤âƒi•–~)d"ÃÀ<o<G˜·D/·w±†¹=³¢43|Õ6á:Ï2R¹¥½‡ÒɔGav._‘—Ľôßõ×gGõ¹aüA§Lï,`½>Ag²¶Xz,•¼?›¼Ý|zU„,±z²<Æw÷·wO†ÌåpC/Ѓ‡»âµ¯žù¶YŽO}›úº,P]Ø [1Ó$ꖔCE•Ö_.¾,X¤©ÓÌ÷kÞèW¼þsq2W„$Œ»b7«Þ÷Þ_"æyendstream +endobj +160 0 obj +888 +endobj +161 0 obj<>>>/Annots 16 0 R>>endobj +162 0 obj<>stream +xڝVËRãFÝó7šEL2’e›GU„GŠÅ0dìd‘!‹¶Ô2 +’Ú£nÃ0Cþ=çv˶PlS…¡dK}Î}õ½§õe/¢Å#þOʽ_'{—Š"šdX ‚#š¤½L…zÌ«™;I®>\yšKÊ5™Z +#SšiYçR“ÊÜr-5«r“«ŠêE!õÉþäxé˜À§ß°ý2/¥o)'¿^ÌeMށçŒ|§ñeÓ¿?1=$? +]X Êwò„ÿÍ£gòNý¿¼ÿ#—¶»@|ûöØkèo [ç–,¿YiNç™Ja’;|+Ä Œª™Ûó\¨ÞíþCkúæP6»wŽÀðì/ëCÎä×¹óò܁Óò㠝ä9ÃU–iiÈ{ïQ!«™¹{9¯óʈi!ßÄÖôY‡ê¾FMîDÝ!>ˆb!_uy§jó"ò| ­P‰pÕiåÕA¯ƒ·îgÞ`÷ùL…šåàÓéõ9ý½Í»yÏ,´ÿ ÖÇO»I?x«ßŸiQ‰ú‰®?Ng=ݾ¾Q`ço‚©^ަ[î¡0/ =UÚEÙºwqvԛù(”º§ E€=4m­ñƒ*iU}OÓ'#IÕ)†ø¶'‚û@4Íg¾¬Ò\T·ûô˜£Û 9Ëtã o'BiãëҒ¡"•q†²¼Ö&pÁS4pæÇq0bR0›•&HTõ _F¾,†…±hh˜Å<§2Ë+ܰü5ªö ¢g×p1œ—–u®•À©Q©jI…åâÑéøìêŠ t è¤t¦ÊR"ÕFÔf•=ÍÕ¶ÑmïÐfÄ3"¸\ÚX~!PðJUþ´Õ½5å,éÆÔ£jkw +( ‡ÓVKx…}Ôr^K̀FóµZԉä;§R$¬ÆÛ‚t¹ù´@…P iÓLÙm/$£( +Cøäú1ÁՓ浚բäõ…–]e:¡ƒÅyT)Cz.Î,sF¶( +š WъrCåq K‚›’Ag܌—þӍñ}Z·ÔaÓ)ƒfìbÔýٌ“:ŸºaÕó\jû€Kr‰±­v1Ù ƒç-_"¾|úâ0DsöGà ¤’âx ›»‚ÆÝÓ¸?-Ûó§·½››sTÔµ§ª1Š\šÔB¦( ÒÝSÜ×1!×uLð-DIƒ¨D;ñmðÃCñEÎJ=[•Éæšª©¤‰LþÝ0 ã“VE¶&†ê#‹´lŽöfKVk@IG#Îpº(ÑÍ#Žv¼~¡™wâ[ˆ’úa•Éf|||Ìmµ ßB?„T¶ð¼%¸í»žßÖä˜zÛgc7{‰S„?¡.ü=b;¹+×a³µ½]‚=@£Ø‘¼X¾8i–4÷z®6J¸%‰4…’ʜŽœGgõta¬Ž#T–£õLL%DkMפñ$‹¹¾´ +±ãÉõò½`å“5êR£­VMaìۢʜD¡‚ÛސþZ}vÚHÞ+‡zWY„Ö‹ £’öpqú£¶«³bùßÅ犐Ö`í8u,žÜï¹(vk3¿h—â u^ësSî£&üb0¢Ñ i»‹WG&à‡#¿ÝxÌöÉ?ì‡Ìñ³AÈn;õ¡¿ïý–—$endstream +endobj +163 0 obj +1237 +endobj +164 0 obj<>>>>>endobj +165 0 obj<>stream +xÚ­VMoã6½çW ܋S¬µ–í8Î=´NÈ![wã( -Q6w)RËüûΐ’b+µ· †aÊä̼yóf¨oW) ñ“ÂíÆSÈʫߖWï?ÞAšÂ²Àél’Ì`™÷ÇÉ$I“d¾²OLy&çºÜ^/¿ Á¤5Œ¦É„ –aa¥µäLsΈ•w”v¢@;pŸP鸡gæÂŸ9·N(æ„VP¡prh +ÖW•62]`Í7ñ Pçc‰á7Ìä;fxËà³`^:Ø2é9 °‚I˓þî-ø˜í8f«s.?ùrÅÍåd êÁ¾&k+žÅlY“Ê þ/ƒ’ü‚ +Ž %zˆ!c+ÞòV´¡ ½6¬ìdê4°ü‹·‘=í]åq@'–.ßË|2_‘ùå¬-&«Ög’δÔ7ù¡ø±•¢Ó!ܑO”Þ`\nµôTÒ÷îPQá”KÍʒA9â7ÅïÊשLq=Âõ×£Ñ)ØAðÜÂå·§õöQ¸S»>0•w î± ( %;PÅzƒP92ŒÒß ™g(Ä~ÇÄÍNXN  ¤r•ÌeЪ!¦¡¤å¹©ðç³(‘ÜS«þÏ[þ Ò¶@–ºA(ԖP¡‹Å=),¶Ãð"_u9þY¡`g؊ñ뚒mSå¨ã’+°WYèlë‘$ç$S¼ô÷/×ðKëågØ7Gg],µuÿÇd‚ºë¦â6FûõæÍÉ®»I3ïÇà S–ú N/ü1bš– +2ú»îœhṴ̂–û#m´õÒ$í½¦w[Cž ›ëíž³ ϽÄA;תk_ß-1ò¥{c´–†³œî2Ã9–ðØ á¯o¹Z +„Žm™l…©Õ“Ù¾ƒL2k9.¨5,7[‘qûᴨǂ­Ï'ï&j +E $Æð()ê›{¶v_•Þ)eÁƒu¼LN Ž}“(òŽîbå䨔Ìi#è¡B ;mr\r—%í=莙¾§¡ò`ä(£Iˆ/Oƒñ8™ÖBJR8_’ŽrŽF,¸²Â:K@Rð¥6dÀ‡ýú<|‡ LË0+ã¦u _ŒvÂmbÚ£|^ú½Ÿz/םfÉðí/©šÅ#H ÛRi5XI¦¾Çѯ}u¬Xn,Öx¬¡ØÒ/¥ÞÅ¢ 4 S,±¸… ÙAÔc0]„ŽÜ;­óZ÷³š¾ôæyžÎn"ÛqdP¡ +–q¸çV¬ýàœ©š s°LÃv’ÅaóЎ*0M™¶×'³arÁà–ž–W\ýìh¥endstream +endobj +166 0 obj +1102 +endobj +167 0 obj<>>>>>endobj +168 0 obj<>stream +xÚ­X]oÛ6}÷¯ ¼—hI´e{8I[H›¬qhéÊf#‘®H%Í¿ß%)[ŽbY20$qê>÷èÜåç >~„Fæ;΋Áù§1 ²HIä{SM)¾.’wW¼€Xó'x¿ø1êQÜjÖAÅßh.…¹òq1ð=Ý½|ûL‘7"Ñd‚'Á؋Hè{!)€ÜtæÍ*4 Co²‡¶üF¿pbN(ž‡<þ¼Ì˜RD°þ2D|r†$C{éÜ^³Ëîó#·ç¾, +YŠDFb»=” n‚ñ:¢™Ww¥øöx4í¢©Ñ‹úÑ+HY™éÿ9’Ê‚è5˜%s<þVš Ö'Ì ðüþaZt[˜ãYæ<Ž #Vo£Ø@ÌSŠ<¯;Ú.Ž¡m7Ïä‡\*|a/d gS Á†ÿ€ŒøU;‚£ç¢ÞÁ:tk°‘YB×"•uœ6eæDÃ/]²Ì܈mò™ÖÁvOvæëN%‡>JŽè¨RêFÆl›ÅÉfà$¦t‚§÷fjÑ­LCj}‘õáÛ ÙH.¬A´$,I¬ý‘:G|‘WìEöÁdçþì-º•½ºBzW E(ôkç3²q¤É´µ=É!_⠏fÑ ÕÖ¡VÛ F¦Úúd4¶L©7F@\nTâÅR¤†G]”1õÂÈ9a¨î`$åþ-…âJ+J`Ò2Ç»I2.À.Íï/¯¯­áØÔĪ)_•…sM²mXL³L>CB–/„ãÖ'–•à­»T¶=F»Íx/1\¤…ÒR&¿;ñ^uÜ3k—fÇ ü ޛªãÚ*nWÇÁÖ@½û0¥§‡žøö8¤ÁRƱ¦MCZw¥n䪑 ™\©sf/þ›¹«–B#UÌ kV%· —WÖqiBƒSê“C÷ˆa%g•)çÆ2ðÏvW}т”±¤0–À$"i!s°ªäHÈZ*ý¡a=úYL®%2g¼«ã‡vàëÛzæn~;Ø)âÀN‘·3ŒlyŸ—zmgœ.Mög¬“ÓL%?‚6؝‚)=auèž:9p«NQ5¦8®Í ‚®!õ»J”ÛyE-|*Ybm”›„ièj‚±¿«Ö=T±è¾ªXp«*˜g£Z•;Yè†" ŽKòpu‡S Î0•6h—R}4³*@CšÊ*]ŠÑ ÕÚ¡û*bÁmŠL_ ²à9ÈR¿qIm“mX]>AYž×8#iž5$) —öŸ^Ý>>>>>endobj +171 0 obj<>stream +xÚ¥XmoÛ6þž_AøÓIJ^üŠº¤kƒfm—xŸZ¢®éRTï×冉,uE'±ž»ã=÷J};KH ? Y¤$›“¼:ûm}6ù}J’„¬K’.¢)™/³hIÖÅ/—¬¤0wT×Ìüºþç,IfÑäá!¯Õx¹œ­Æ >X%ÑÊ}»c9/9«‰¹c¤p*H:hn˜& )B‰wë³8Šá0íÇÍ{’NÑþbö©4ŽR¢¹}œd+0êÐÖþ)pš%-8ÍbülÑ@s|žÉ£ã×Tnºeçy£5“†•SÁ†x/¼¢>Çg °1Øq‹ê¸w:žÍ—ûÀÛqëàܑsÃʦs%%Ë W²&¥V•õ¸öþäNÕæec2N2°¢’™¥¿ž¥I¡*Êe#ð™zF² ¾8͈EÛ³ž{F,Ø1rD·Œ$ÖùK•7ÄúF©0ÿ'M­'5¤5›äÍ®ž*?™ +^)¨¡Dƒ>Rp ü)½ï#!žFñð´°è¡iaÁ]i1[®\Z¼ÓZékµ (j[O>û[¸‡]Þ[̖”\0[9˜8=ŽÏl#ê¸Ct܁;ŸgèÃ{­š]à3FîœÔûÚ~V…åñÔñ-ª ’V sþ꾤†ðš@ äáŽÉ Dt#%—[¡YJ*ÈN«­¦UÝÇÕ,ަƒ+Å¡VŠwUÊ,ö'ÿÿ ½Vê+DÀÛç²l™Ê²§D À•F†$ԅQdÇt©t–îÌrõ% ‰…fu ™d¡Ì–K9Œ™xÃþƒ¼¿"ÝÒFFŸå Žà`£ˆ|ðèVaNÃÈÔ|+á¼ðÀˆ=´vˆJÁ¬EZ*sˆr‰_¢}¹…Á§ÁÂK¢¤Í†J‘—ŸOjL éúÌw²e#m“Ť€\[¢¯aLçÇ®¹œ÷ՍCÛÀœ»\p`— Gô!¦Yì}UíϹ¹´†Yæ‚lS!ñæT2ÐÆÀ¬0À¼âsͨ Þi.q¹È=[XŽ_¨7i ?@”d­Œ©1l"@0 +f AC*ùBPý0³ùEžeTO„âi[­3¤àt„,Úòu +ì#dÁ.BGô!BÙÒ¯8Û½üžuÇæYC{èb–¶ëuX¡h`l-"Öhö¿˜ÊI;üúûšCìkÜÕײY|tÄú±æSM¸dñé @+ÕÀØÇüy$í+(ìbí¸Tj¹Û°Ó8ªÆÀû–ç,;îøÊÚr_Ùq‡|¯¿^_ûéNvÔܽ |=9<~s$Ò7îZ!h»1 Ðøæ¹NŸã 0ª“øG¶H‡ÊI|j‹L>‡`wº†Q&Â;”,Õ³Vx¡¤ÑJ„ÙƒX]yü ՖÃ\¾°rEäú Ԟ=%lÓlGá‚>B+£s2z Zâo«edö‘Yøô »0&d ¯táú̳ d¬éUéôG¡Cl„ÜÕÓ$véú}¼6ópJ%q|bL!Å}äUSÙTt»$5ü/ •Ð'êpcª¾ÇB¶¶"²¾ƒÞSÑØQcg“´NðŠãÐ1*АL²Ã˜2ÊÀŠs´Kï)tÄ v W°:×|7¾%2YNÛæÑ ‡ îŠFÍvrËÿ çÒÐXÔ z`Éõ‡sW +aªSY@ƒÚ²¶D0d³7 ‚sUâ{ +l61j’0ïñ'ö €øZƒ\·ªàZ—<›JXžO·»¨L…ƒ"ö˜3V°¢/Tð¹*‹* î U|(›ö­V|2X/ŽÄ0V8ÁˆÕ†Q·õŽ˜à.ÂÜÒ|PÙCiøɂŽ‹íš‹…óã36ǀ©·B¨‡óÃk—®ë³o«%±p‚©‹"þ ‚_➬à +3úó+¼È؝ έü9ä~CûgÝãå î¨RØùzÇö6¡)JCgÚÀ¿Ò%\27,ŽŽæœg¡g6¤‘ý†ÌW}±=¦@õ}ˆÅOëuãføiý¾Kñ³Š§óÛëðãú38¹ö öeðÒ¿ Nì;ÃE·WØ+œR%…kî%Ãë0þ²£–Œå؉Œ½LÍ -ðíXÁbk_L—ñ!ÇW>üžýcPÒPendstream +endobj +172 0 obj +1632 +endobj +173 0 obj<>>>>>endobj +174 0 obj<>stream +xÚµX]oÛ6}ϯ¸È^Z`±EIþÈP˒¶3Ð^â< (0Ðm³“H•¤’z¿~—¤,ۊmÉ+†N"R÷ž{îóí‚@€_¢¡ýNò‹ßfý÷1³„QÜ»†á˜ôÆ0K_•"cZƒY±5PÅ e‚³æøÜ1±†Œ Ö{=ûzñnvô<ºþ¸ÿa܋a8àaø°žòpJ¢kûâN؝có½Ù‘ÎØÝsó½ÙŸÃÞð?؜ïí´v`xÑåkHð9ÆtJ—ì£\Ú 2Àg}šÉ¥î¸ôWæ×®í¡né¡` _pæt™L¨áR€\¸¿í|¸„ÏZ¥0°ïóo ƒVfÚÙq +\¹ïÀa Û[tí<ÊÚ z*•ix>ŒHíïÐS´õ˜B;@”ùœ)0¯ ö·…Tðûl6µ›¸"¾÷&R–X†t.¨Þ’(§Ùphgå)pņ{6¶èš€à'Úz?™ÞÒdÅŒŒóã„Økþۄ?g¹TkHì1À–Ãtƒ³¢¸†Rûځ¯µj1LµQ4Ñƒ®ytGŠ<øEƒQ\yÎÔS7iÎEƒ%%¥ùÕ/¦9;•3z*hP†&ž¹YA¡ä€û^îp°’Úˆ]ç7!ß÷ƒtY™í$HÉ¡Â5atf+ã7Í´ôòÁ )Cå`<˜;;e Zf¦qÂíãô´3Û%ªEºg“éüñ@­ ¾˜µ†ó)¨Bۜ8‡v|œW!p`‚-ºA0ò…ˇà5×Aÿ‰ª~Rú”­V!å + “ÍVËHENJ u¥»•‚€Ô©ØA…ÝU…|L…ñ˜8‡ÖXxóJ–ŁDüôZ»®^K{89:EY2üá( ª›Å‹–¸I˜J(-$ŘOqçzåÑë•«Wñ öæÎX^ÜquH$&/Ni À^GQ[¡—umNÇ㺏µ+ã;*Ï*Ã}Z§yÎdÙ̌(šJ˜Y?=Ø6+Ͱ§æ EÀ6ua§ƒ7µà@Òªw»öÇÓ4s͐¢mßJ¦M[$>£¥ytW‰8ð1‰D׎«GLüæìWœÎ”€‚½&þŒ)ª‚‹eƒ#ö«³ ™ínKE[»[4&g¤ŒGwäÃðя*¶÷ªNõ½­æÂ &¨‚…µ|{7B'Ãa%8ÛÔw‘®„ZåhœµÕ¬+¹••½#¹G7·“ æÙwӃ[™çVl~Qªª¡ÀÍ ²)|yuùÓå—×ÍÞ¸¢ +'¦zÕÂÆ¦w8‚âjžQñ·;؟«·»ªçÄjæËRùYÞg<bX ³L>û9ãÖ'š•Ì6âÍÒˈכµ»#¢éȊ‘2ýÅó7¨øÚ8\mrön³Ë‚B<+òb¼c:Q¼°fN¸Ó“ÛˎGGø9Ú¯$;w_kYT3ÏM’0´Bì\”^$¦²ê§‹JnZÙlÁžá«œã$󉮱ÌÔAhV–Ë?™¾´Š¹ü,/[2†Œ·ó`{Æx´wüeQ £Ø‡ã͝Ÿ£¦•ÖÈ· #ßô«Õ·/9)•²¢Õ{\àlÆw +³]–n†5ü©‘Ÿ.•཮û%É£:¯°'ž°ÇûI£ î½Ô¡®JŁ£ø¼4¬%+Ûlg(Ô£(ÔÛ~œˆ…l~ãjJ‰57Ý&O}?ïfêNWê`ªC55¼(>Vÿ*8jî‹ÿ%t²õ:>ã:äÀÇ,^üŸ°Läõñþ#c4Ê&3C4MœÑvŽx•Wæ‹3ÌÅu¿k7߁›قêóòJÚÖI¦Vw—A¦w£«òK#>>>>>endobj +177 0 obj<>stream +xÚmÍNÄ0 „ïyŠQOpXÓ$mÓ7~µ7 Ý(© AKZÚ¼¿Hºq@–lÉúƞùy, £ +ØOqӊ«‡R¢  ¨jM5Úþ¢ ]àËöCHYRei7±uƒãáá¼ ®;aI$Æa]N³óçkØÎ㕑úggdM§‰ûŒÒÕûVä”G;¿íåªHŒ‰Î_UN +3£ù–zOûÖJ‘ùC¯¹ê-—,M>>>>>endobj +180 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS045×3S072PIÑp VðÌ+I-JKLNUpI-ÎLÏQÉE™%™ùyš!Y\º-ºP=†F AcKK0×XÏTÏX¡ (dJ±^r~^HÞ5„+ §($Öendstream +endobj +181 0 obj +123 +endobj +182 0 obj<>>>>>endobj +183 0 obj<>stream +xڍ—MoÛ8†ïþƒžœƒR’õQ ‡:M…Û8·\(‰^kWµ•Øÿ¾CRrW²„l¾>3|9”ÿŸQ øG!tÁ =ÌVÛÙý÷\ÛŽ¡ÛlîÃãQqY²Ö%>ìXÊë»í¿FKC«]ÔqÚ¡ðµªžDúW°‘B‰TVî¥­Ü |»çòª•C^+!Z$¹‚´àø¼}ØÜ¯7P[a*ʒ§*¥:DÆw¬)h—¯yÊ¡Ré81%Ĉ4®L= úük ®ö"ƒ’¸–~²Ñ?9dç'²Ù¹ðð¼y‚•ou^þ3-Ãþ)&Kxþ¦[$¬æ$R°,eµêÒp`u:g§ö8£ËOT\2Åk%¦}•܇"uÚñꑥû‹Å*fªšñ:•y‚1B× +ÃØ!£Æ.0šÌµ@HÜVë=ÊÚ­úúô°^ƒâG$WRg‰› +”ê/É^rÒà¼Ì´ð-W{\£äoE^rx™“#a/wvcÛ`¸ÈNÈS +‹Äô‡¢Àj~¶U'뢣‰®IO*O›6|hd?þþ¸G £¿Ø%;´Ãs3ùã”¹ÉøJ‡±¯U¯¬h0ÁTHÉëJଃ®éz³Ž¹·E] -÷Q~QÄn"®¿¨›Jo5Ïþ °€Iƒå¾¶@Oƺl½©X§îù‘e<ÍØ Êæ Ú푼ÂDy©ô‡”U,ɋ\îÍ>àî6jن¥KÝ&nhQV¹Òãaˆ‰ýÅ7cÄJŸo=𸝇`³:ÿûõÚ*ÀžãÉô>º§KÜî>qà ÓÀw µéz]ÂԏuTk c[;pó|éÁ•£)Ž˜31ÂëÆºü&¦çáÓM^+¶¼ïj䵔n`(陲ƒÑ˜…HYÑ)ùA¨ë^ø2gÅ;Õ@_îÆðÏ÷uUn'à¿ü]ýž€·´uuÏ)s1±©˜RÃjŒw5˜j+î±@KD—Ö’Þ-"ìÝBŽQ‘¸Ûè TFRr´Ò¨ðm`zû­}ÿ=:¿(‘›?^üP÷ ‹íµd?g¿›Á6¨endstream +endobj +184 0 obj +995 +endobj +185 0 obj<>>>/Annots 21 0 R>>endobj +186 0 obj<>stream +xÚ­XÛnÛ8}ÏW ú”•*êîö!M“E€¦›M¼ûÔZ¢mº-E%q¿~‡Û²l+Z´H‘ÔÒáÌ93ÃáÐÿ^ðð‡@«Yyñi~ññ6B`¾Î\q¸)ÌóK¼Ÿ¿e‚7nyÁ£}‰xàø±Y0/ÜE'9{æsrÖ°*g¨ñ*¯¬mD½´4k\˜¯Þ´ZutŀǃX‰‰,¢ÐÇ*)x Ê3Ÿ +£•…¶ŽsÖ¢Ý˱@¢«³F‰ºÑÞjäï>qÞá{ÄÏR¬‡Q|Q‚FîlßG >\oßC”ÿ *Çø>ñaxÀÿÓQˆÄjwÚ£Ä~Ù¦î‘-™`UÆàžV->`’¹Èá&ç’וJÁ nÑø¥«ž;ÚÇ®ÎTqÜßÝ߀Ü4 –µ€Ó•Ç[0µêÙZ½¤MSðŒ*Ÿ«Üͺ¦u\×êu‡•m|÷·†zFeˆD´ÏGÚJ&&l a€#[Â"x©‚eprM%du%)Ö)=Ø. +dL@Î3%ˆŠŽ!8$À¢cZåãnÄFGÑlm,Úí×YW"XïÖõXw-nì RЪÅ|ZsÇ9•–¢.µµmÅh/ïZeíˆ$¾E«û<3!µ-Ë^;À…tàX7PÝ;QWI¥kßoSqÕÏ,؊W-¼p¹Æè.ëNÀb#±ïnðduÅèJ—Z俁÷ù1‰‚$„o—ïé“|÷í½Žß‚¯$αƒS‘­¹d™ì„i݃tx¯IhÆWFä}Ü)¸”;iÇ´ÃÁózÙ„Öñ‹BeF¿¨ó3Ӝþñ t´FsU-þ¯mêªå6n˜å™W+ŒŠ`{•te´ ãT™i_pC)œ +H c9Ë݁gE_ +I/)í¾X±;]¥‹¸…˜;¤ˆÌ¶v²Æ|âÞ-ŠÍ0«·uQÔ/ЇÒu*{ºv)´Lpä‰!´nUÑcxov •TÈ]IôvÙ°Âw{Ö&Žº´‘±æ¢N–²d˜JɊ †ç¨xUœuu+¶ÑD¶wD3ԖmŸTdÕë˜à=-|f¦[Ù¦IÒÀ<ÿ‡Ýȼ¦êÔOvôP cãÂ,ÄSÆ`‰¡ã1°ïy8)´¤xÞ f‹mOŒˆbYežëqR“ÑîUÀ® ÚjƱ~ñµ+Œ\ɱ¸1´WO×ww˜*Üì«7äF*jåjìd¹}B®$¦NâÐ!~rJf]Ôâ—É Ÿ(Sc'ËÔè³2ÕÁˆã«Ÿ:dFN¨œãýËDœ8¦ŠÔØÉ"5úœH2‹íígæ;~Êü³“M'¥N2SCÆ4;U§AŸÕ‰W}ƒò£uÎu^åÏg·Ï;d• Åzê0ö·Pª6»ᕄ˜­ø‡ÃQŠÔ¼ïžM§ö‹$ÞäÆe°“£¢Ñg£h~ìáqœŒ‰®ô}@¶§’‡—º¯êôjp ðlœ#êæwÕ{ t¹=ÖHÿ4ò{½ƒÓÀ–É0< TÒx.fÉ6I€AK…†š¸ŒaM&4Ø$bÞ&"±»Ðǖêǃ–ŠÝ´Àm¶O‚-e•ƒ¼†ªVS¤†à߆fú~8¼AÛ~¨ËòX4ԐÚh°‰À¼@d+1Åá`Ðl¯;9¨Bï°³NB¹E „ãâSµ7҉}W?Ð«OAî#ZöBVü¤UÛÚ'Sµzy(~Önˆ‰ þ[ËÁ¬ÛqÐ3TºýFNŔøÞîf¹Ÿ©q0ä« +ó¡c–8vý~ ­Û/ŸÆ¾æÁøëâ?„'endstream +endobj +187 0 obj +1530 +endobj +188 0 obj<>>>>>endobj +189 0 obj<>stream +xÚ¥˜ËrÛ8E÷þ +,gªB ¹˜MœxÆ©8ñXJeMS„ _áÎóõi )J‚ø@Êå*[& à²ûvƒß¯(qᇒ%#< Ivõv}õ׍G(%ë-a._p„t’õæFþ&×mCª"MI¼mDE¾®¿]¹Ä¡|ÁÄ/¡Z4ä]Be¼Šz¿¾r.¬ªÿõðñÂŒ^´ðÔ%õo@*AVhä-"KôdÖìt\úډ™ë*Ý~w½ÙÙÀôÕS{<´fOçÍÎFªu@TøT‰ÅÔ*–ÌaK_=0/€gꪋïÚ2?Ô5êú02@օ‡}_ɼ!µÌw©pj¹#"hmŠöñš¨]©ïç¾oRaÍ⺦àNM3PÁ=¡{ÜCB,‡…ü\…¿>ˆºHÛFùQ ¼UTòg‘71}¾!O¢jdÿTý"s ©RTŽÌ“ýbZ?òa)ú˙ ¿¦$@—3£H£Gú ¿ôµ¡ç°(:à6‹wð ßm¾Ñ/Câ¦h+Øj#v¢ªÉN>Gš½ ©Ø6oÈcÑ4Eö†Tr·‡•VMQSµT’Õ¤Øê±ÊA`(~+|ø¡Ä, øšzFĀÁÒìâYÛ8Bz,Ž|¢Üuîqt›×«½@÷¼H©wɋö¨0ðØ2®â¦·U#êôº''´a‘uŽ!k­¦Ç´ñ"•ñ@™å¹2ŠÝQa.ö’@MÚéXÒàÃá^Wu¶2ưá2gR]Ó "­7â«eO‰‰,îq +F1‘F1t/&÷»U»¡Ã)=—ó£ˆUƼß`¾”u]”DÀ]"k¬ª›aTªNRJ×·:±'1%ìGpKhBW7:$𼮚µÖUÓcºòè +e «áƒwq>X5@ïM9š’”ò0™)³ô,ö¡4küÈÚ?ÒcÆÏƒfQ[fàYŒ›[ÎÛ8½X¹Ç,+ÓTúB¶’Lld<QwÃԄ$~_ g­ +Y[«Bz̪xoã ̊fu§~ßÕ*#nóšà:MՌl+ +êù4³]HêÀ64kšFfÂéÀv¿ +åÆfõò¬o©(ßUqVèsàÙj÷üÞÆÕ\ËÇ©ÈôùMkÖzӚÛ4ƒñsÈtn4¾w²ªŠJ·¯“q¯1RV‡ô6#Þ¼?® ™uYFÖ6֑‹uÐÎñx:Ž÷IìâF>‰Y%d®zßq%nÍûJèS¥šµVBÓ£Jp¯KŒÐ3ŒðS›]¥¦ûS•ØL]T§ìP²ý%}Jná<Yðq‚…Ö©¬mj =–4ê…ûó ûû\Ižsó»èÙԛ€DÿÀì.ŽwI>ø…“¤Eòÿ³¬‡ú·u[åH·¥:H™ê9h4Îæ=o\fôñ6Ûk kÛk =ÖkPo‰¢ql×7l÷sÛ@)¹‰ñ¥L<Ȉ!1¨´åŒ +º£´Ë:dm³鱬£Œj |paßpŸ{xŠ+ùS)÷Unš½î¸R‘ïà£e‡E¡ ¸–ù„¬m>!=–O0!Æg¾¾²ÂÛ:öN¼gIŠL÷{ÊÑW-I‘ªcàùœãŠ„ÔÚi5jûÈ5<þ²¥ ûÜ%0Üe]Å/«gÙ$û©j“ì㼸&r NEÒ@S©®¨#†ÈÊæe@¥këg“Ð:Q4j+š†Ç[R” œbi8źÍS3G.X<‰¼;Ü>ïáãF¿Ûƒcâ\Zè+Ð(̖ ò¨`v"QúÊYUÍv©ÝNtO_;/¾`ýÕvkÀqýôÛú°k¨¿„Ð_2ýD¯¿Ü¯ ‚B©ýü¨å.W’J–‡jìà§ãÁÔzWš•ÉM÷‚Ä[z‡ØÃø] üwõ ø‚­Cendstream +endobj +190 0 obj +1472 +endobj +191 0 obj<>>>/Annots 40 0 R>>endobj +192 0 obj<>stream +xÚř]o›H†ïó+æ2•bÊ0ÃW¤½Ø¸M[¥Öf¯V‘zC`l³ÅÀŽ›¿ç̀Á d[)jdãÃ3Üw^Î ôß JLøG sð/Ü\Ü,.ÞßrB)Y,‰e2ƒÇ£†GÑ%%¿‘yV• âY¤$V¢$»5FÛ<?âtõnñÏÅÇŅi˜Ðñþcþ‰pÏp‰ãÚЄˆe)y8ƒúÜðG¢^7ÝvÉÏvl™&¦þÚñn&?Ý5gÞh¶Ûïæ %Ž&Ö¦(–C g“¹Ö„¹6Nw Wƒá6/ÿŽ£jajÚWq#ÙRÎ9‰7òÿI90ç¶ ”—°Ì!%«®«ƒëT%mA¢f‡Þ'Ê)ô"u Qÿ4ÑÏ"^­«£LUð¦Ê°›‘©Jvtª’îMÕ¢ÂT=sÂ?Û·áúãòSìØüݗŸí™ª<3ϛ0Ÿöfx>Îç›YcÒs9\fdz’ž¤{Ós̺^ùP¯ü3õêæ¥˜ß×8çÒ;´³etœÉv< ŠÍG7ŎVEÒ½ªXn}ÇûPÜü3ÅMúù"SS¦™°‡ëmúý¥.käÛåtöxGößÞa+ô¨›àÚÿ¤‘ˆ:M¦S2›ÍÈãã#¹»;mcA›< Ò 8hc6Ã/h‰_оT{Ö¦×Ü`ðá赖¬ÊZ×ZKZiÝҍ֜qe +nšn²­ò ìøÏöU#Ôz·Ž+qFÐù§›3’Aô÷£0Cõ“ ü~ç‡é:ŠÚ}œM¢ŽbïŽÂ®‚Ã„ïN»öëp¸ÑÏsüf®(ÃCÝd)¸±¨†V³¥p5[¼™.fsU¹ÉaºÜs Q–q–¾ÝrÈàsl=UìØÊ¡è¾ÊÁWõ”›Þ„Ó3ËÅ<ÛM³mZ½¡6–7ºª*v´6’îՆ6w:µ@û¬6·BDo( ”ª±[LŎ–FÒ}ÒXУ*9Ôiü³Ò’ +vÙd™dú×ý™e% +²ŒxTŽK¢Ò3ëô.ƒ|½Ð°°ñ°Ösõl{~C¨Åõp†akéØ˲ M Ý€v†Ý€ööâôÐ^G=\ܖ¾9Q»X‘vú™CÜz¹„„gǾ֘à=ôpM>¦aa¶ËdQi™g…\Mê‹¼Tc‡‰kxíí2Âð\Ä;ÈcjVN·†mÏ7vÐÀ ±ƒŽnÆºm3|% ¡[hw`$ì@]ùŠ ¦‡íàÔËQmgس,‰ôƒØ@„å/÷ǧÁÚ òXㅚ•s­aÛó誇;ÐÜǧ& Ýè{ ïڕÛ Ýà:ÐwP>³µt íãr²§‡Ã=5µsÜkòA”ñ*%Ÿ²qí ҁ…é—šÌÆ4òXcšš•¦Ð°íy˜*6Ðq@Óàðut  ix“@Ÿix›¡eºÕÑMãëûî@3|÷¨£[W6G>úõÓ-€+›­W°àÊ6@w 9ӏ„ÁvÉßÓö€‚hØbëéÀÿ¨ð ïú„ÃÿÓÒ÷³;7w [KÜ9‰Úmâ.í¡*¶aµ…n¶”¶bïww ûúÛÓ«‡‚%–OGnre_Ë M!ø ÷yU¿—˜PՁûÚRï2 2ØÌxêÑêü¾î÷?/þy¾F‹endstream +endobj +193 0 obj +1620 +endobj +194 0 obj<>>>/Annots 45 0 R>>endobj +195 0 obj<>stream +xÚÝWێâF}ç+Jû4+=¶+å`„4‰xöi¤UÝ†ÎÚÝÞv3,ùúTû†1÷d#E’ øÔé®:ÕUåï-,üØÐs í‚·>{­‡‰¶ ^NßtÀíwÌ>xÁÝ«ãöà£÷Gkìµ,ÓBC}±õeþ„榅Ø6bcp³]üˆ`qÝ˜Ý +Ýï]@×1ØÎïçàuâÝAæÅ| øs‰¿†ˆÁ±m³s_G ¾mU‘:¯!ß³M·†ÿ|}¹„‡I§Ð¬íî›OÁ麃Oð+IƗðFՆRϳÀt6ƒ™Jø"Jµ¶;j« 6Ñp\ô½…—ùbªV"Nb +¡KáK’fƳ³y|™-  !ã4µÒQ$6z;ô‡¢¦U±)c-Ùz?3Êüijvě’4~™¦/§ðŒ‡âZl,$=npÄˀ¾3Ÿ^v²q6ª·Yabœ)†n«…Öý€ìN%.)í*‰rp,n÷PÍÀ a†}-dÕI³ÈËðȰ!椾d‰‚˜l‹&”%”n^zcXÜàM[¦!.òN"#3®Òð+[ ú¸‰w Jo»^j $%J—xŒV)N%óa&RµÈÙó¸8V;Ù!¾áüÞCá> ²Æ.ٟy»dñF£ÒCrÄb—7U”¶óˆ*Ú,*£ñóØ7ëJçB] r®ÃÒ"i,ÞÏW”sMùšâq¢îüýâ~[½ifÑh??-‘B±æÁ•Iq6ñÎ'F7›õE÷†ƒÇçáb1®fƒî³_°Ü<”†ÿÉ ôæŸ ýâ·Ýíé÷·›ûšMýÓªxâˆÎ–\ß²:W´0#72zŽõ&ûNO¿÷dLv¯xQý½õH—Gîendstream +endobj +196 0 obj +1004 +endobj +197 0 obj<>>>/Annots 48 0 R>>endobj +198 0 obj<>stream +xÚ՗ßoâ8Çßù+FûD¥K. 4¤'ÝzÚ +i{¾UªLâP÷;ë˜ívÿúã@~·Zí^Õ +”ð±gæ3ãäsÏÿ\øú?Êz×aï÷›+p‡&ø‹¸¶aÜÚ¾íÃ8Ža’’¢€‡þäþnù8žN'óñr ‚óuè8þÃÅEøŒ>†àºÆ‡åùöPûŸ(ôm=ˆœJ¢˜àú^J4OID P(,r±„ÑRnƒ¶6®ÒuŸ(%Ùj£haEODT5×îÿÖ4À½¸O͔µ‘$µRÂײ¦m@xÜ^9—Œ+*­d-9TžHŠA}Þ0Ic[ëZÉ8â4Ñ61o6rDÏx"ÎÕfBÒâÌh¶2AÇ£,ãÚ'¶3¼ÇbEbK‡H‹7¼iŒX4³U3°ÍuÕpÖ`€}V6ܦ4¥Š6{n:›ÏÂY³íF'Ú.6~ڝ'i&¾t5œàX¶}9›hŸÓ[GÚ²£‘l7¶Ù™ÖóðÃðIĆÇg¢Ð‰[7Œ£ˆæ +nۚÀ“Éì.|¼ýt½‡!85ƒ—gí¥6…ÓT¼æ®°Úé°î«×!1¢ÏøÖ®›“Ãá?Ïð_˸–§÷ÆÊ,è3š¬,f·³I“•«¬Hã¥ÅJ.éÊUIK"E†¼l‡öw"Óæ¤y†¾dµt½7d\–TᑓMª¿÷Ûñ³œ…xú܌ïç᎟ñ ~°8Xz㱆@ã Ò2gÐþ¹ ª‚qnIz-Íö¾vJüµ:®Zu^?©£§åùp-äòùt4Þ.ª+@G¥ÕÐÁco èæŒS¸+ ?%øìÂñR(‰TΞc;øB£?\ý±ø ¼Ë¡} ‡œgàÛ1),ÍËNnP6ƒæöÐZýùÝôáÙ3k+t"ÄÀL¼ã›¨ÖÍ`à\bLûM¼Uרö ½K] Pí»ÈJ—ºd0tÜ]n«kT;¹~¨\ï²]&rq3Á䎮þ8YºÊ“Sz2,XÆac¤Ü/>BF‘Ô8ÉèvB`at5>¤yü¡„((ëê^Žp7¾ïô ƒz ¾kê)ÇÖ\aóÝ[—eŒ¬‘çh7Ð7½a`ÀùŽ·adâïÞ¿ž}Zendstream +endobj +199 0 obj +927 +endobj +200 0 obj<>>>/Annots 51 0 R>>endobj +201 0 obj<>stream +xڍ‘1oÂ0„÷üŠ 86Ð:BKŀDIØXLòÒÆ1µÝJý÷µ Zu¨,=Ëö}Ͼó[$ÀýH'˜&(T´Ì£x½€H‘Wþ$IS– /‡36GFæƒ ¶d­¬ ËV¯Øít¡ÛQþâÉ„èÉñ$a³@ægú›<³íò8‚ìJj¥£+­”î°é™ŽÖMëéOëHyýj³Î>>>>>endobj +204 0 obj<>stream +xÚ-‹Ë +Â0D÷ùŠYê¢5Iíc]àB¨4~@‰·%ZM‚߯Q™Ãœ'àŸUª¾³V±Õ¾P#DYçjÉ¡.‹Í¹ëq°‘ü8h–‚™líÍ#g—êʲŸ’ýÉ,D™K|Á:oГ‘Ç‘B&B;;}Cç]tÚÍé¿SìÄÞ+E*Zendstream +endobj +205 0 obj +137 +endobj +206 0 obj<>>>>>endobj +207 0 obj<>stream +xÚ­–Ár›0†ï~Š=º3µ1ıÓk“´“CfÜ íµ#K – ¯Dgòö]“:Ä1†dÌÁ OüÚw‘v£fü aÁÅd>ú‚o_ šAœðÈb9‡X/á&p£ ¥3¤Ñ~Š·Ì- =ÇS'ÑbZ£Ae)Xë¢!æDx1<ošÑÙ~t,E!1{9eü¹Mee7±ëFè $ňB½æ¬®E‚4yΰB«Â §/ýšÚQfû:&¤ÄÒuE"«Òªîp…ÊÛòÇ0yŽ)„[.’1e#Ã)k´¾[DÆ8Pû"}“ÔO¯®À'JKP‰²çO§E2,¤C‹®ö#љ¿õSýs˜ÂÙ^EÁõhHX–oûïßõ¾ÕäFµ;´½+ò2CX­nÞ'õVƒ£‹¿‚>¨òäU•!%¬…üƒ…:øڗZÿ ™êIççúû”dRù S$åòä xV§qš¢n¢û»ûہ ”‘ç +3ZåX¸Fx ^“…Ó’þÕÃÓ¥ ž—‰'Êñá‘+?‡_ð sœ¤K7@/3©í½Yû›çuí"Hdè(xd/)EŠGØ¡‰*KÕÑÎÿ[˜KÒ ]؃¯YbPÈ 7Eíñy¢„» +­³ý•Knq]¤lͺYÇ^öêI–n“(ŒÞ<¦Í—óéåx< +ýƒÛxôcô¡«Æ8endstream +endobj +208 0 obj +540 +endobj +209 0 obj<>>>>>endobj +210 0 obj<>stream +xÚ-‹A +Â0D÷ÿ³ÔE4‰&u­Up§ ñ·|ÁTÓÜ•xÃ{“žb°òµñIÛ@ËÃÆ t0®Yx4V#Üg»ëé‚c*œ»[d´>>>>>endobj +213 0 obj<>stream +xڝ•ÁrÚ0†ï<Åۃ 6 ¤Gââ uìÌô*äÅQ‘%*‰Rúô• ¥0S+ÁãíúÛýW¿ÌN=÷ aA¬ê<䝻Ɉz¯\d8@^|ÃT(c¨Þο7 áè ÃnÔ¤tCÈQWæ1„0¬35ˆ†Ý†Bƒ³PØ?> LU›­E ‚ÊrKKì^‚‚óô ÕTíÀ eÁe JƒF†ügý£ –B¥4‚}£ÒÉ^r Ô]`yå/È7èë^I vt_«¨¶’3j¹’˜+#QÀíQ‚Ý)ØhUjZ_9ƒšÓ©»A“QlÖ§ÊµÛ¨’®}¥×-꺗žœ—‚A¯{pEc¦•ÜûŒ1Îâ4õ4R¹q0·a™¥² º€X+§>•î^5ý¸ïÎ>uO%zTǯ$k/;…õú’~¢¹´õ`³½±Xy˜IߑvhB²ÅËšo + 6ò$÷p'\ äšJ³Âš¦¬bJxhO$˜ÎÚyO¸hm@([׍N5ݼqf`v<’~4‰o`µ»aH«•¸¶ÄóJ<«å5ø4É'íðÆ\î@"K.ÑÒ#§f ¥™—KÈØ“Ù®ØÆ4[¼GlN'ÓXè’Jþ» xØ3òØÎž9å§±>R¬¼¨y:OÚYó­¨_P§pœrɯwϰ×iÄmó-¶">ÅD›1Í7öŸn4͂ŽÙüá½?öÿ¾/þO£[îՁ¨_/$yçkç÷É­endstream +endobj +214 0 obj +573 +endobj +215 0 obj<>>>>>endobj +216 0 obj<>stream +xÚUÑ‚ …ïyŠÿ².4AEn³²uÑf‹À:Š Ð¹õöAÚEƒñoçœïüã…0$þ`Hi¸âJŽVUo¡ @Y3à×ÅYºQ:8ʾo: ¥¶â¾ä7Ÿ¦s:ò Ncâ¼âõdÿÊþ\§FÕh¨”–À]cúÖw×ÎVX=qlæXS Ø?Ü\ê3Ì ]Û [٫΄!œzʚÀF8/|<*H’1KÃ†½¶þîŒG'ô SGpendstream +endobj +217 0 obj +195 +endobj +218 0 obj<>>>/Annots 93 0 R>>endobj +219 0 obj<>stream +xÚ͜Ks7€ïúsÜBã=3‡=Èí²Ë^kEæ–*Cd&|hIʎÿ}ðè4FÀT´&“*[p7>sºFèÿñŠÙÿyU‹Jšj¾:{=={õ¦­«¦·×mejUMoþ5ý¶ìªÍmu±Yï»õ~÷Óô÷³ñôŒ˜%¸_¸ûåú­TFêQS­ªf$àçe5qìúö®zõFWœ»¿ÍM3VÕþm¼z‘«Êÿ–ðƒ(“ùæ¾s ¡-ÜþÁèäÿãÏ>·}(k !FÆ>¸# xðWo˜ÑúÑi%Ύ£Œ% deçrgKŠ9 ÞÝX¯/nóÙ~±Y;¨®íŒ²kÉv¬©Þv~ê,ÆÙH‹‰’ŀÙ³n +rD]næ+k´çyaJÙß ( ñÓ×nûuÑ}s@%ì'=²õy6 èFÚ_C?÷±—¼nü“‰ü‚G”nm0&¬ õŒëî¶Ûvëyçs“jGõ‰¯z™XmZŸå|T…ÁS‹]×,¤;Q\ìHl„ý-!1’.~¹šdgÛ Õ̹„²‚Y¸ +ú´aÌqÝR²º61ņALÚæ<l]JÈiØH¦éÓþK·Í;N·Æ–.$0 +@œÄ +ù4aJ`šð??•&¤KÌöQd!QÌ>»NiA +”w¶†Ù®gËça°ªZ3¤˜âng˜yN/ïèBÌó:¤W™~ðd¦á~EËrž^Ûôð$öçâËl;›ïsÑO®DQ.±P\Û lÒåöY2Ó­"ãbrPÁ£Þ,–Á‘‚Ä*9I²MøIXLÀińks“r@ ¤³õÝÃì®ËzÍô8.Xÿ!{¯È'ëÍÍÛQ{2+§`tÕ²¸K„A4ºjyHÇr$ FGN£­ˆôñÝÇq&óÅÙ®.uÛCÂ9°¨ÁÍi¥ªç­^ gõºö•rëxaOhϯªnB•l­žËPd²«¹ë! +ä[-VÝhÿý¾/*å‘-V2‘Q¸e50 &2vÑQ6É¡Â) +äó&šoÖ_½‰ô‘S¦),\ÍãVdáj°Ž*-[ pƆ{ÐÕf·ŸÌ·‹ûìQ tŽI€¨ˆÛÅ:»cR€Å5õ#(xÜe·óϖæ$¬*Á\öN‘  †ÙåDž‚)¬ +Y‡½Í®U!Ü#U9q‰‹ºç&«aù3nau3„Y…Èÿ¹ïÖ;ë¤]†HÎñ.S¥Äš|ºý&çï8×ú›‹G$PÖÕÕåó0:ÝÂlðÕ) šGÕÀÿ;xJ™B(²ÅûÉBã¯K¹8­[ Ä@šÌ¿t7Ël9ÖÅÆÛ’AÀ‹Íúvq÷°–7á¸ÀÑv $TTЃòA°#ôÿêÂBçœT~@º 5¨ty¡‰+W%%(l¾œívÝÎ퀷§°,$Û&a-$}…J’\ß²NQ Øüá~wÓÛG¹Ãô‘«Î¦`#»Xo#? 6jpáçª{2ՕPÂYˆ‚@îQ÷aS'!¤ŽÚYç,Û°‘º gëÝðó é[µö T¾aƒ0[O´)-HâvÀ|Æ|®e) Ā4lÔ©ƒF¼Ð¥”JǗaðTÇFÚÅæ“”*ölÈ™ÓM Ôùýýd3ÿ#Ûo! —\îLˆ¨È«íf¿™o–(ݟ×EãKá_°‹ÄÊ@úúڛ¼ÔqAŽo˜'é€v<¢¸hlVJX ÖëíæÛn±¾Ë•¦᪠·í'@Tbâ¼#µ>‹ãm<õ…ñ˜`Á_¥f R‚E)%ˆçoÈõóë”ätÐñ‘ B;£M ˆ®vóŵ>rƒ«‚ØŽMÍ0 cð‚_êÈ f¥›ƒßx!Šs÷F(fewHÞ[[S Ð_}ªùüv<ý|9~sþˇéólJ³lɆl«Éÿ΀ÈT 2føäV!‚ØŸŠ1þëO¡þ[ÑÊ }¡e<‡‰1©¡Ø5@„\_HÒbHBEzæ¹Þ)!ØðªÝ«³” +jW×ïþ3_gö +[ù\3@£‚*j;K@mù@êŸ7â‹Ñ!ÛØ`Ša½fŠ=$qîÞÀ%¨ GØùÍM.Bâì>Q( ¬ü^… ¬ßé`P@ Éùå%IƵ„æbD Ù €ìl”(‚’œ[{§¨ €('Æ  +Ё"ÂU¦àKAn2¹@5V‡&WړÉáÈ+RÈñRT·ìö]þÀ+"Î0WP*¯+±òõààó¡!V.ÇÆÓñáB€ÖÇL ñ¨øÜîB&»mª:åÃEýãp) —±‹$H¸ê ÑÜ!‚LîwŠ9ÀÙoV:e¡À.Â+b6 0î4”A€d˹øp>™Œs;¡¹l"‡lTv6›H‚’œ ŸåÃC÷»Î ”ËÅHaŒT¾Œ¥•/ã±ò5¥Hl r€²ï Kéþ3¦ûÂ|¤dp`}©šG8¥#Œì9>J2Ž%$ËÕõk"7!dê +޾)H×äãüd|@”Þç¸ +}í1JxÓ×&u!F6„òæð §‡ù·= šCB„LwË]Û™Â@¡y¼Õ”¢„À,ºQC4*«25œ´ø +±&©_*JбQËX¹†‰ZÅʵ)EBG/A`çóyWîéö8_ä'8TÞûÍoّä1C)™Ò´Œ,Ì!ã«éç÷Ÿ^OJukOö•eBFu`݊¨P·¦(PP¤nm^²n-…‰a±n &†Çºµ-… ¸/ªÈvÝýÞÍ÷ùf–‰8å®Ï&8T^!LÈ|·%´Ã‡ +<)Z¯ÇïÇÅ@!4‚͐ +¼X±ÒÉ+ß6(pR±¶/w>(V\.õÅs‘`QM¬_9Ëõ›ãtW—´.kR*¯p>Nï÷œ +; %áV A¡Ԓ‹·QqŠ +MROkÉEš;ëð¡P¡)ÖÅt²EÕlø1Q¡!uñyŸ­þÖ[œL°ù¦=—*¾ŒƒØ´çRc\šöÈ©ÝI&á€HëLiCf»øo\HQÈõèÀÛ¬„°òöðP€—³n•½ë¦^óèYQA?ñnûÇ_L(ú^ËÌa@|/ÀóMÉó@±5K) !»l¿f¿¨¦ÈâÂçeÊj’>v»]öû#tvÈU*„ ËÍü|ž"°–M… +®ð Þfï]µª¿vÕª§o]µpGSç/]µxƒÔڂ¢¼¬Œˆó\¡0`!@~ÎÕâ¿~A!AËÅÖÖA›í"¼MÕüT¿Ø+ò߇6p]ÒÕî†\–´¸(yžË„8Ë/w™‚ o—»¾¶ß}·§ñæ9kµârCŽsïjµ~>Rγ·Üz€]CÁ˜é¼ÐC¦Ýv^۟ؿop¨ÁWgÜ#ùŸéµu8fï¦õÃ\š„¤È™o7ëï+¼E)OË\ÁPñYÿOŽ49Úh¦®É=»þjhe+ÖÅݺ"ߑñKJ¸îç:\¨Z€ÿ{ö¼¦øendstream +endobj +220 0 obj +2965 +endobj +221 0 obj<>>>>>endobj +222 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS045×3S072PIÑp VðÌ+I-JKLNUpI-ÎLÏQÉE™%™ùyš!Y\º-ºP=™™ A×®@. Àýendstream +endobj +223 0 obj +98 +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<>1<>2<>4<>]>>>>endobj +xref +0 268 +0000000000 65535 f +0000000015 00000 n +0000000226 00000 n +0000001792 00000 n +0000001866 00000 n +0000001944 00000 n +0000002021 00000 n +0000002100 00000 n +0000002176 00000 n +0000002257 00000 n +0000002315 00000 n +0000002430 00000 n +0000002515 00000 n +0000002630 00000 n +0000002715 00000 n +0000002830 00000 n +0000002914 00000 n +0000002952 00000 n +0000003053 00000 n +0000003138 00000 n +0000003239 00000 n +0000003324 00000 n +0000003355 00000 n +0000003421 00000 n +0000003504 00000 n +0000003570 00000 n +0000003654 00000 n +0000003720 00000 n +0000003802 00000 n +0000003868 00000 n +0000003951 00000 n +0000004017 00000 n +0000004098 00000 n +0000004164 00000 n +0000004246 00000 n +0000004312 00000 n +0000004393 00000 n +0000004459 00000 n +0000004541 00000 n +0000004607 00000 n +0000004690 00000 n +0000004770 00000 n +0000004836 00000 n +0000004921 00000 n +0000004987 00000 n +0000005072 00000 n +0000005103 00000 n +0000005169 00000 n +0000005254 00000 n +0000005278 00000 n +0000005334 00000 n +0000005418 00000 n +0000005442 00000 n +0000005546 00000 n +0000005651 00000 n +0000005756 00000 n +0000005860 00000 n +0000005965 00000 n +0000006070 00000 n +0000006174 00000 n +0000006279 00000 n +0000006384 00000 n +0000006489 00000 n +0000006594 00000 n +0000006699 00000 n +0000006804 00000 n +0000006909 00000 n +0000007014 00000 n +0000007119 00000 n +0000007224 00000 n +0000007329 00000 n +0000007433 00000 n +0000007538 00000 n +0000007643 00000 n +0000007748 00000 n +0000007853 00000 n +0000007958 00000 n +0000008063 00000 n +0000008168 00000 n +0000008273 00000 n +0000008378 00000 n +0000008483 00000 n +0000008588 00000 n +0000008693 00000 n +0000008798 00000 n +0000008903 00000 n +0000009008 00000 n +0000009113 00000 n +0000009218 00000 n +0000009323 00000 n +0000009427 00000 n +0000009531 00000 n +0000009635 00000 n +0000009738 00000 n +0000010042 00000 n +0000010074 00000 n +0000010106 00000 n +0000010684 00000 n +0000010732 00000 n +0000010780 00000 n +0000010828 00000 n +0000010877 00000 n +0000010926 00000 n +0000010975 00000 n +0000011024 00000 n +0000011073 00000 n +0000011122 00000 n +0000011171 00000 n +0000011220 00000 n +0000011269 00000 n +0000011318 00000 n +0000011367 00000 n +0000011416 00000 n +0000011465 00000 n +0000011514 00000 n +0000011563 00000 n +0000011612 00000 n +0000011661 00000 n +0000011710 00000 n +0000011759 00000 n +0000011808 00000 n +0000011857 00000 n +0000011906 00000 n +0000011955 00000 n +0000012004 00000 n +0000012053 00000 n +0000012102 00000 n +0000012151 00000 n +0000012200 00000 n +0000012249 00000 n +0000012298 00000 n +0000012347 00000 n +0000012396 00000 n +0000012445 00000 n +0000012494 00000 n +0000012543 00000 n +0000012592 00000 n +0000012641 00000 n +0000012690 00000 n +0000012739 00000 n +0000013032 00000 n +0000013184 00000 n +0000019543 00000 n +0000019565 00000 n +0000019660 00000 n +0000019762 00000 n +0000019782 00000 n +0000019922 00000 n +0000020377 00000 n +0000020398 00000 n +0000020511 00000 n +0000020695 00000 n +0000020716 00000 n +0000020856 00000 n +0000021620 00000 n +0000021641 00000 n +0000021754 00000 n +0000021943 00000 n +0000021964 00000 n +0000022104 00000 n +0000023063 00000 n +0000023084 00000 n +0000023238 00000 n +0000024546 00000 n +0000024568 00000 n +0000024717 00000 n +0000025890 00000 n +0000025912 00000 n +0000026052 00000 n +0000027483 00000 n +0000027505 00000 n +0000027627 00000 n +0000029330 00000 n +0000029352 00000 n +0000029492 00000 n +0000031034 00000 n +0000031056 00000 n +0000031178 00000 n +0000031485 00000 n +0000031506 00000 n +0000031619 00000 n +0000031813 00000 n +0000031834 00000 n +0000031992 00000 n +0000033058 00000 n +0000033079 00000 n +0000033242 00000 n +0000034843 00000 n +0000034865 00000 n +0000034987 00000 n +0000036530 00000 n +0000036552 00000 n +0000036715 00000 n +0000038406 00000 n +0000038428 00000 n +0000038591 00000 n +0000039666 00000 n +0000039688 00000 n +0000039842 00000 n +0000040840 00000 n +0000040861 00000 n +0000041006 00000 n +0000041398 00000 n +0000041419 00000 n +0000041532 00000 n +0000041740 00000 n +0000041761 00000 n +0000041910 00000 n +0000042521 00000 n +0000042542 00000 n +0000042655 00000 n +0000042849 00000 n +0000042870 00000 n +0000043010 00000 n +0000043654 00000 n +0000043675 00000 n +0000043806 00000 n +0000044072 00000 n +0000044093 00000 n +0000044247 00000 n +0000047283 00000 n +0000047305 00000 n +0000047418 00000 n +0000047587 00000 n +0000047607 00000 n +0000047662 00000 n +0000047767 00000 n +0000047911 00000 n +0000048017 00000 n +0000048126 00000 n +0000048275 00000 n +0000048385 00000 n +0000048492 00000 n +0000048650 00000 n +0000048761 00000 n +0000048880 00000 n +0000049031 00000 n +0000049135 00000 n +0000049239 00000 n +0000049416 00000 n +0000049525 00000 n +0000049682 00000 n +0000049788 00000 n +0000049905 00000 n +0000050012 00000 n +0000050170 00000 n +0000050280 00000 n +0000050407 00000 n +0000050532 00000 n +0000050653 00000 n +0000050772 00000 n +0000050940 00000 n +0000051087 00000 n +0000051237 00000 n +0000051385 00000 n +0000051539 00000 n +0000051687 00000 n +0000051831 00000 n +0000051981 00000 n +0000052129 00000 n +0000052277 00000 n +0000052425 00000 n +0000052558 00000 n +0000052679 00000 n +0000052797 00000 n +0000052931 00000 n +0000053028 00000 n +0000053128 00000 n +trailer +<> +startxref +53355 +%%EOF diff --git a/doc/idd.shtml b/doc/idd.shtml new file mode 100644 index 0000000000..63bc383747 --- /dev/null +++ b/doc/idd.shtml @@ -0,0 +1,1128 @@ + + + + + + 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.1. + + + +

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

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

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>
Surrounds a class definition.
<DefaultClass name>
+ </Class>
Surrounds a class definition for the default destination.
AcceptingSpecifies whether the class is accepting new jobs. May be + the names "Yes" or "No".
InfoA textual description of the class.
LocationA textual location of the class.
MoreInfoA URL pointing to additional information on the class.
PrinterSpecifies a printer that is a member of the class.
+ +

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
AccessLoglogs/access_logSpecifies the location of the access log file.
Allow-Allows connections from the specified host, network, or + domain.
AuthClass-Specifies what level of authentication is required; may be either + "User", "System", or "Group".
AuthTypeNoneSpecifies the type of authentication to perform; may be either + "None" or "Basic".
BrowseAddress255.255.255.255Specifies a broadcast address to send CUPS browsing packets to.
BrowseInterval30Specifies the number of seconds between browsing updates.
BrowsePort631Specifies the UDP port number to use for browse packets.
BrowseTimeout300Specifies the number of seconds to wait until remote destinations + are removed from the local destination list.
BrowsingOnSpecifies whether or not printer and class browsing is enabled; can + be "On" or "Off".
DefaultCharsetiso-8859-1Specifies the default character set.
DefaultLanguagecurrent localeSpecifies the default language.
Deny-Refuses connections from the specified host, network, or + domain.
DocumentRoot/usr/share/cups/docSpecifies the document data root directory.
ErrorLoglogs/error_logSpecifies the error log file location.
Grouproot, sys, systemSpecifies the group name or ID that is used when running + external programs.
HostNameLookupsOffSpecifies whether or not to perform reverse IP address lookups to + get the actual hostname; may be "On" or "Off". Hostname lookups can + significantly degrade the performance of the CUPS server if one or + more DNS servers is not functioning properly.
ImplicitClassesOnSpecifies whether or not to automatically create printer classes + when more than one printer or class of the same name is detected on + the network; may be "On" or "Off".
KeepAliveOnSpecifies whether or not to use the HTTP Keep-Alive feature; may + be "On" or "Off".
KeepAliveTimeout30Specifies the amount of time to keep the HTTP connection alive + before closing it.
<Location path>
+ </Location>
-Specifies a location to restrict access to.
LogLevelinfoControls the amount of information that is logged in the + error log file. Can be one of "debug", "info", "warn", "error", + or "none", in decreasing order or verbosity.
MaxClients100Specifies the maximum number of simultaneous active clients. + This value is internally limited to 1/3 of the total number of + availabel file descriptors.
MaxLogSize0Specifies the maximum size of the access, error, and page + log files in bytes. If set to 0 then no maximum size is set. + Log files are rotated automatically when this size is + exceeded.
MaxRequestSize0Specifies the maximum size of HTTP requests in bytes. If set to 0 + then there is no maximum.
OrderAllow,DenySpecifies the order of Allow and Deny directive processing; can + be "Deny,Allow" to implicitly deny hosts unless they are allowed by + an Allow line, or "Allow,Deny" to implicitly allow hosts unless they + are denied by a Deny line.
PageLoglogs/page_logSpecifies the location of the page log file.
Port631Specifies a port number to listen to for HTTP connections.
RIPCache8mSpecifies the size of the memory cache in bytes that is used by + RIP filters.
ServerAdminroot@ServerNameSpecifies the person to contact with problems.
ServerNamehostnameSpecifies the hostname that is supplied to HTTP clients. This + is also used to determine the default CUPS server for the CUPS IPP + client applications.
ServerRoot/var/cupsSpecifies the root directory for server data files.
SystemGrouproot, sys, systemSpecifies the group name used for System class authentication.
TempDir/var/tmpSpecifies the temporary directory to use.
Timeout300The timeout in seconds before client connections are closed + in the middle of a request.
UserlpSpecifies the user that is used when running external programs.
+ +

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
AcceptingSpecifies whether the printer is accepting new jobs. May be + the names "Yes" or "No".
<DefaultPrinter name>
+ </Printer>
Surrounds the printer definition for a default destination.
DeviceURISpecifies the device-uri attribute for the printer.
InfoA textual description of the printer.
LocationA textual location of the printer.
MoreInfoA URL pointing to additional information on the printer.
<Printer name>
+ </Printer>
Surrounds the printer definition.
StateSpecifies the initial state of the printer; can be "Idle" or + "Stopped".
+ +

External Interfaces

+ +

AppSocket Protocol

+ +

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

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

Internet Printing Protocol

+ +

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

+ +

The URI method name for IPP is "ipp". + +

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

The URI method name for LPD is "lpd". + +

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

The URI method name for SMB is "smb". + +

5 - Directories

+ +
+ +
/usr/bin +
The cancel, lp, lpq, + lpr, lprm, and lpstat commands + reside here. + +
/usr/sbin +
The accept, cupsd, + lpadmin, lpc, and reject + commands reside 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. + +
+ + + + + diff --git a/doc/images/accept-jobs.gif b/doc/images/accept-jobs.gif new file mode 100644 index 0000000000..9da7a0dce1 Binary files /dev/null and b/doc/images/accept-jobs.gif differ diff --git a/doc/images/add-class.gif b/doc/images/add-class.gif new file mode 100644 index 0000000000..0f43a6fcdf Binary files /dev/null and b/doc/images/add-class.gif differ diff --git a/doc/images/add-printer.gif b/doc/images/add-printer.gif new file mode 100644 index 0000000000..90d17eb3f1 Binary files /dev/null and b/doc/images/add-printer.gif differ diff --git a/doc/images/cancel-job.gif b/doc/images/cancel-job.gif new file mode 100644 index 0000000000..3cc1e23bc6 Binary files /dev/null and b/doc/images/cancel-job.gif differ diff --git a/doc/images/cancel-jobs.gif b/doc/images/cancel-jobs.gif new file mode 100644 index 0000000000..2384b903c6 Binary files /dev/null and b/doc/images/cancel-jobs.gif differ diff --git a/doc/images/cancel.gif b/doc/images/cancel.gif new file mode 100644 index 0000000000..e994606782 Binary files /dev/null and b/doc/images/cancel.gif differ 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/continue.gif b/doc/images/continue.gif new file mode 100644 index 0000000000..ff774adb34 Binary files /dev/null and b/doc/images/continue.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/delete-class.gif b/doc/images/delete-class.gif new file mode 100644 index 0000000000..81b1465acd Binary files /dev/null and b/doc/images/delete-class.gif differ diff --git a/doc/images/delete-printer.gif b/doc/images/delete-printer.gif new file mode 100644 index 0000000000..41ce85d788 Binary files /dev/null and b/doc/images/delete-printer.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/hold-job.gif b/doc/images/hold-job.gif new file mode 100644 index 0000000000..ebd448ae9f Binary files /dev/null and b/doc/images/hold-job.gif differ diff --git a/doc/images/left.gif b/doc/images/left.gif new file mode 100644 index 0000000000..fd7b041043 Binary files /dev/null and b/doc/images/left.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/manage-classes.gif b/doc/images/manage-classes.gif new file mode 100644 index 0000000000..69d5b01470 Binary files /dev/null and b/doc/images/manage-classes.gif differ diff --git a/doc/images/manage-jobs.gif b/doc/images/manage-jobs.gif new file mode 100644 index 0000000000..adaff856f0 Binary files /dev/null and b/doc/images/manage-jobs.gif differ diff --git a/doc/images/manage-printers.gif b/doc/images/manage-printers.gif new file mode 100644 index 0000000000..cd897291dd Binary files /dev/null and b/doc/images/manage-printers.gif differ diff --git a/doc/images/modify-class.gif b/doc/images/modify-class.gif new file mode 100644 index 0000000000..58a0ead829 Binary files /dev/null and b/doc/images/modify-class.gif differ diff --git a/doc/images/modify-printer.gif b/doc/images/modify-printer.gif new file mode 100644 index 0000000000..593b5f8818 Binary files /dev/null and b/doc/images/modify-printer.gif differ diff --git a/doc/images/navbar.gif b/doc/images/navbar.gif new file mode 100644 index 0000000000..c19f634c0d 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/print-test-page.gif b/doc/images/print-test-page.gif new file mode 100644 index 0000000000..807dca10e6 Binary files /dev/null and b/doc/images/print-test-page.gif 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/images/reject-jobs.gif b/doc/images/reject-jobs.gif new file mode 100644 index 0000000000..6d938e3084 Binary files /dev/null and b/doc/images/reject-jobs.gif differ diff --git a/doc/images/release-job.gif b/doc/images/release-job.gif new file mode 100644 index 0000000000..a05cd9cc71 Binary files /dev/null and b/doc/images/release-job.gif differ diff --git a/doc/images/restart-job.gif b/doc/images/restart-job.gif new file mode 100644 index 0000000000..a007efc5b4 Binary files /dev/null and b/doc/images/restart-job.gif differ diff --git a/doc/images/right.gif b/doc/images/right.gif new file mode 100644 index 0000000000..8ae8213cea Binary files /dev/null and b/doc/images/right.gif differ diff --git a/doc/images/show-active.gif b/doc/images/show-active.gif new file mode 100644 index 0000000000..d232ef9f84 Binary files /dev/null and b/doc/images/show-active.gif differ diff --git a/doc/images/show-completed.gif b/doc/images/show-completed.gif new file mode 100644 index 0000000000..efd206cd54 Binary files /dev/null and b/doc/images/show-completed.gif differ diff --git a/doc/images/start-class.gif b/doc/images/start-class.gif new file mode 100644 index 0000000000..2b6f43fad3 Binary files /dev/null and b/doc/images/start-class.gif differ diff --git a/doc/images/start-printer.gif b/doc/images/start-printer.gif new file mode 100644 index 0000000000..017bb394aa Binary files /dev/null and b/doc/images/start-printer.gif differ diff --git a/doc/images/stop-class.gif b/doc/images/stop-class.gif new file mode 100644 index 0000000000..5cb7adfd80 Binary files /dev/null and b/doc/images/stop-class.gif differ diff --git a/doc/images/stop-printer.gif b/doc/images/stop-printer.gif new file mode 100644 index 0000000000..b3accf3dfb Binary files /dev/null and b/doc/images/stop-printer.gif differ diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000000..b6fd277344 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,36 @@ + + + Common UNIX Printing System + + + Easy Software Products Home Page + Do Administration Tasks + Manage Printer Classes Status + On-Line Help + Manage Jobs + Manage Printers + Download the Current CUPS Software + + + + +
+ +
+ +

Do Administration Tasks

+

Manage Printer Classes

+

On-Line Help

+

Manage Jobs

+

Manage Printers

+

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-2000 by Easy Software Products, +All Rights Reserved. + + + diff --git a/doc/ipp.html b/doc/ipp.html new file mode 100644 index 0000000000..0ab96c1323 --- /dev/null +++ b/doc/ipp.html @@ -0,0 +1,1250 @@ + + + +CUPS Implementation of IPP + + + + + + + +


+

CUPS Implementation of IPP


+CUPS-IPP-1.1
+Easy Software Products
+Copyright 1997-2000, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Overview + +4 Operations + +5 Attributes + +
+

1 Scope

+

1.1 Identification

+

This document provides an overview of the Internet Printing Protocol +("IPP") version 1.1 as implemented in the Common UNIX Printing System +("CUPS") Version 1.1.

+

1.2 Document Overview

+

This document is organized into the following sections:

+ +

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

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

2.2 Other Documents

+

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

+
    +
  • Adobe PostScript Printer Description File Format Specification, + Version 4.3.
  • +
  • Adobe PostScript Language Reference, Third Edition.
  • +
  • IPP: Job and Printer Set Operations
  • +
  • IPP/1.1: Encoding and Transport
  • +
  • IPP/1.1: Implementers Guide
  • +
  • IPP/1.1: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
  • RFC 2567, Design Goals for an Internet Printing Protocol
  • +
  • RFC 2568, Rationale for the Structure of the Model and Protocol + for the Internet Printing Protocol
  • +
  • RFC 2569, Mapping between LPD and IPP Protocols
  • +
  • RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1
  • +
  • RFC 2617, HTTP Authentication: Basic and Digest Access + Authentication
  • +
+

3 Overview

+

CUPS 1.1 implements IPP/1.1 and the operations and attributes +defined in the "IPP: Job and Printer Set Operations", "IPP/1.1: +Output-bin Attribute Extension", and "IPP/1.1: finishings 'fold',' +trim', and 'bale' attribute values extension" specifications.

+

CUPS also provides 12 new operations and many new attributes to +support multiple IPP printers and printer classes on a single host.

+

3.1 IPP URIs

+

CUPS supports both the "http" and "ipp" method names. The following +resource names are used:

+
+
method://hostname:port/
+
Can be used for all "get" operations.
+
method://hostname:port/admin
+
Used for all administrative operations.
+
method://hostname:port/classes/name
+
Specifies a printer class.
+
method://hostname:port/jobs/id
+
Specifies a job.
+
method://hostname:port/printers/name
+
Specifies a printer.
+
+

So a typical printer URI would be +"ipp://foo.bar.com/printers/LaserJet".

+

In addition, the CUPS server also supports normal browser access to +"method://hostname:port/admin/", "method://hostname:port/classes/", +"method://hostname:port/jobs/", and "method://hostname:port/printers/" +to view and manage resources on the server dynamically.

+

3.2 CUPS IPP Operations

+

CUPS provides 12 extension operations in addition to most of the +standard IPP and registered extension operations: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operation NameCUPS +CodeBrief Description
Print-Job1.0 +0x0002Print a file.
Validate-Job1.0 +0x0004Validate job attributes.
Create-Job1.1 +0x0005Create a print job.
Send-Document1.1 +0x0006Send a file for a print job.
Cancel-Job1.0 +0x0008Cancel a print job.
Get-Job-Attributes1.0 +0x0009Get job attributes.
Get-Jobs1.0 +0x000AGet all jobs.
Get-Printer-Attributes1.00x000BGet printer attributes.
Hold-Job1.1 +0x000CHold a job for printing.
Release-Job1.1 +0x000DRelease a job for printing.
Pause-Printer1.0 +0x0010Pause printing on a printer.
Resume-Printer1.0 +0x0011Resume printing on a printer.
Purge-Jobs1.0 +0x0012Purge all jobs.
Set-Job-Attributes1.1 +0x0014Set attributes for a pending or held job.
CUPS-Get-Default1.0 +0x4001Get the default destination.
CUPS-Get-Printers1.0 +0x4002Get all of the available printers.
CUPS-Add-Printer1.0 +0x4003Add or modify a printer.
CUPS-Delete-Printer1.00x4004Delete a printer.
CUPS-Get-Classes1.0 +0x4005Get all of the available printer classes.
CUPS-Add-Class1.0 +0x4006Add or modify a printer class.
CUPS-Delete-Class1.0 +0x4007Delete a printer class.
CUPS-Accept-Jobs1.0 +0x4008Accept jobs on a printer or printer class.
CUPS-Reject-Jobs1.0 +0x4009Reject jobs on a printer or printer class.
CUPS-Set-Default1.0 +0x400ASet the default destination.
CUPS-Get-Devices1.1 +0x400BGet all of the available devices.
CUPS-Get-PPDs1.1 +0x400CGet all of the available PPDs.
+
+

+

4 Operations

+

The following sections describe the operations supported by CUPS. In +the interest of brevity, operations which use only the standard IPP +attributes are not described.

+

4.1 Print-Job Operation

+

The Print-Job operation (0x0002) prints a file.

+

4.1.1 Print-Job Request

+

The following groups of attributes are supplied as part of the +Print-Job Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

Group 2: Job Template Attributes

+
    +

    "banner-end" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page that is printed after +any files in the print job. The name of "none" is reserved to indicate +that no banner page should be printed. If the client does not specify +this attribute then the value of the "banner-end-default" printer +object attribute is used.

    +

    "banner-start" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page that is printed before +any files in the print job. The name of "none" is reserved to indicate +that no banner page should be printed. If the client does not specify +this attribute then the value of the "banner-start-default" printer +object attribute is used.

    +

    Other Job Template Attributes

    +
+

The Print-Job Request is followed by a file to be printed.

+

4.1.2 Print-Job Response

+

The following groups of attributes are send as part of the Print-Job +Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Job Attributes

+
    +

    Standard Job Attributes

    +
+

4.2 Create-Job Operation

+

The Create-Job operation (0x0005) creates a new, empty print job.

+

4.2.1 Create-Job Request

+

The following groups of attributes are supplied as part of the +Create-Job Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

Group 2: Job Template Attributes

+
    +

    "banner-end" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page that is printed after +any files in the print job. The name of "none" is reserved to indicate +that no banner page should be printed. If the client does not specify +this attribute then the value of the "banner-end-default" printer +object attribute is used.

    +

    "banner-start" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page that is printed before +any files in the print job. The name of "none" is reserved to indicate +that no banner page should be printed. If the client does not specify +this attribute then the value of the "banner-start-default" printer +object attribute is used.

    +

    Standard Job Template Attributes

    +
+

4.2.2 Create-Job Response

+

The following groups of attributes are send as part of the +Create-Job Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Job Attributes

+
    +

    Standard Job Attributes

    +
+

4.3 Set-Job-Attributes Operation

+

The Set-Job-Attributes operation (0x0002) prints a file.

+

4.3.1 Set-Job-Attributes Request

+

The following groups of attributes are supplied as part of the +Set-Job-Attributes Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri) and "job-id" (integer)

    +

    OR

    +

    "job-uri":

    +

    The client MUST supply a URI for the specified printer and a job ID +number, or the job URI.

    +
+

Group 2: Job Template Attributes

+
    +

    "job-printer-uri" (uri):

    +

    The client OPTIONALLY supplies the URI of a new printer destination +for the job. The new URI MUST utilize the same IPP server (i.e. you +cannot move the job to a different server).

    +

    NOTE: This attribute is defined to be READ-ONLY in the + current IETF specification for this operation. CUPS allows the + "job-printer-uri" attribute to be changed, which makes the CUPS + implementation non-conforming for this particular operation.

    +

    "banner-end" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page that is printed after +any files in the print job. The name of "none" is reserved to indicate +that no banner page should be printed. If the client does not specify +this attribute then the value of the "banner-end-default" printer +object attribute is used.

    +

    "banner-start" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page that is printed before +any files in the print job. The name of "none" is reserved to indicate +that no banner page should be printed. If the client does not specify +this attribute then the value of the "banner-start-default" printer +object attribute is used.

    +

    Other Job Template Attributes

    +
+

4.3.2 Set-Job-Attributes Response

+

The following groups of attributes are send as part of the +Set-Job-Attributes Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.4 CUPS-Get-Default Operation

+

The CUPS-Get-Default operation (0x4001) returns the default printer +URI and attributes.

+

4.4.1 CUPS-Get-Default Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Default Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or +attribute group names in whose values the requester is interested. If +the client omits this attribute, the server responds as if this +attribute had been supplied with a value of 'all'.

    +
+

4.4.2 CUPS-Get-Default Response

+

The following groups of attributes are send as part of the +CUPS-Get-Default Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Printer Object Attributes

+
    +

    The set of requested attributes and their current values.

    +
+

4.5 CUPS-Get-Printers Operation

+

The CUPS-Get-Printers operation (0x4002) returns the printer +attributes for every printer known to the system. This may include +printers that are not served directly by the server.

+

4.5.1 CUPS-Get-Printers Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Printers Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number +of printers that are returned.

    +

    "printer-info" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printers are returned.

    +

    "printer-location" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printers are returned.

    +

    "printer-type" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type enumeration to select +which printers are returned.

    +

    "printer-type-mask" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type mask enumeration to +select which bits are used in the "printer-type" attribute.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or +attribute group names in whose values the requester is interested. If +the client omits this attribute, the server responds as if this +attribute had been supplied with a value of 'all'.

    +
+

4.5.2 CUPS-Get-Printers Response

+

The following groups of attributes are send as part of the +CUPS-Get-Printers Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Printer Object Attributes

+
    +

    The set of requested attributes and their current values for each +printer.

    +
+

4.5.3 CUPS-Add-Printer Operation

+

The CUPS-Add-Printer operation (0x4003) adds a new printer or +modifies an existing printer on the system.

+

4.5.4 CUPS-Add-Printer Request

+

The following groups of attributes are supplied as part of the +CUPS-Add-Printer Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

Group 2: Printer Object Attributes

+
    +

    "banner-end-default" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page name that is printed +after files in a job. The reserved name "none" is used to specify that +no banner page should be printed.

    +

    "banner-start-default" (name(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a banner page name that is printed +before files in a job. The reserved name "none" is used to specify +that no banner page should be printed.

    +

    "device-uri" (uri):

    +

    The client OPTIONALLY supplies a device URI for the specified +printer.

    +

    "ppd-name" (name(127)):

    +

    The client OPTIONALLY supplies a PPD name for the specified + printer.

    +

    "printer-is-accepting-jobs" (boolean):

    +

    The client OPTIONALLY supplies this boolean attribute indicating +whether or not the printer object should accept new jobs.

    +

    "printer-info" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating the + printer information string.

    +

    "printer-location" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +location of the printer.

    +

    "printer-more-info" (uri):

    +

    The client OPTIONALLY supplies this attribute indicating a URI for +additional printer information.

    +

    "printer-state" (type2 enum):

    +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the printer. Only the "idle" and "stopped" + enumerations are recognized.

    +

    "printer-state-message" (text(MAX)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +reason for the current printer state.

    +

    "requesting-user-name-allowed" (1setof name(127))

    +

    OR

    +

    "requesting-user-name-denied" (1setof name(127)):

    +

    The client OPTIONALLY supplies one of these attributes to specify +an access control list for incoming print jobs. The special name +"ALLUSERS" is reserved to indicate that all users are allowed or +denied.

    +
+

The CUPS-Add-Printer Request can optionally be followed by a PPD +file or System V interface script to be used for the printer. The +"ppd-name" attribute overrides any file that is attached to the end of +the request with a local CUPS PPD file.

+

4.5.5 CUPS-Add-Printer Response

+

The following groups of attributes are send as part of the +CUPS-Add-Printer Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.6 CUPS-Delete-Printer Operation

+

The CUPS-Delete-Printer operation (0x4004) removes an existing +printer from the system.

+

4.6.1 CUPS-Delete-Printer Request

+

The following groups of attributes are supplied as part of the +CUPS-Delete-Printer Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer.

    +
+

4.6.2 CUPS-Delete-Printer Response

+

The following groups of attributes are send as part of the +CUPS-Delete-Printer Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.7 CUPS-Get-Classes Operation

+

The CUPS-Get-Classes operation (0x4005) returns the printer +attributes for every printer class known to the system. This may +include printer classes that are not served directly by the server.

+

4.7.1 CUPS-Get-Classes Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Classes Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number +of printer classes that are returned.

    +

    "printer-info" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printer classes are returned.

    +

    "printer-location" (text(127)):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies this attribute to select which +printer classes are returned.

    +

    "printer-type" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type enumeration to select +which printer classes are returned.

    +

    "printer-type-mask" (type2 enum):

    +

    (CUPS 1.1 and higher)

    +

    The client OPTIONALLY supplies a printer type mask enumeration to +select which bits are used in the "printer-type" attribute.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or +attribute group names in whose values the requester is interested. If +the client omits this attribute, the server responds as if this +attribute had been supplied with a value of 'all'.

    +
+

4.7.2 CUPS-Get-Classes Response

+

The following groups of attributes are send as part of the +CUPS-Get-Classes Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Printer Class Object Attributes

+
    +

    The set of requested attributes and their current values for each +printer class.

    +
+

4.8 CUPS-Add-Class Operation

+

The CUPS-Add-Class operation (0x4006) adds a new printer class or +modifies and existing printer class on the system.

+

4.8.1 CUPS-Add-Class Request

+

The following groups of attributes are supplied as part of the +CUPS-Add-Class Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer class.

    +
+

Group 2: Printer Object Attributes

+
    +

    "member-uris" (1setof uri):

    +

    The client OPTIONALLY supplies the "member-uris" set specifying the +printers and printer classes that are part of the class.

    +

    "printer-is-accepting-jobs" (boolean):

    +

    The client OPTIONALLY supplies this boolean attribute indicating +whether or not the printer object should accept new jobs.

    +

    "printer-info" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating the + printer information string.

    +

    "printer-location" (text(127)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +location of the printer.

    +

    "printer-more-info" (uri):

    +

    The client OPTIONALLY supplies this attribute indicating a URI for +additional printer information.

    +

    "printer-state" (type2 enum):

    +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the printer. Only the "idle" and "stopped" + enumerations are recognized.

    +

    "printer-state-message" (text(MAX)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +reason for the current printer state.

    +

    "requesting-user-name-allowed" (1setof name(127))

    +

    OR

    +

    "requesting-user-name-denied" (1setof name(127)):

    +

    The client OPTIONALLY supplies one of these attributes to specify +an access control list for incoming print jobs. The special name +"ALLUSERS" is reserved to indicate that all users are allowed or +denied.

    +
+

4.8.2 CUPS-Add-Class Response

+

The following groups of attributes are send as part of the +CUPS-Add-Class Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.9 CUPS-Delete-Class Operation

+

The CUPS-Delete-Class operation (0x4007) removes an existing printer +class from the system.

+

4.9.1 CUPS-Delete-Class Request

+

The following groups of attributes are supplied as part of the +CUPS-Delete-Class Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer class.

    +
+

4.9.2 CUPS-Delete-Class Response

+

The following groups of attributes are send as part of the +CUPS-Delete-Class Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.10 CUPS-Accept-Jobs Operation

+

The CUPS-Accept-Jobs operation (0x4008) sets the +"printer-is-accepting-jobs" attribute to true for the specified printer +or printer class.

+

4.10.1 CUPS-Accept-Jobs Request

+

The following groups of attributes are supplied as part of the +CUPS-Accept-Jobs Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer or printer +class.

    +
+

4.10.2 CUPS-Accept-Jobs Response

+

The following groups of attributes are send as part of the +CUPS-Accept-Jobs Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.11 CUPS-Reject-Jobs Operation

+

The CUPS-Reject-Jobs operation (0x4009) sets +the"printer-is-accepting-jobs" attribute to false for the specified +printer or printer class.

+

4.11.1 CUPS-Reject-Jobs Request

+

The following groups of attributes are supplied as part of the +CUPS-Reject-Jobs Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer or printer +class.

    +
+

Group 2: Printer Object Attributes

+
    +

    "printer-state-message" (text(MAX)):

    +

    The client OPTIONALLY supplies this attribute indicating a textual +reason for the current printer state.

    +
+

4.11.2 CUPS-Reject-Jobs Response

+

The following groups of attributes are send as part of the +CUPS-Reject-Jobs Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.12 CUPS-Set-Default Operation

+

The CUPS-Set-Default operation (0x400A) sets the default printer +destination for all clients when a resource name of "/printers" is +specified.

+

4.12.1 CUPS-Set-Default Request

+

The following groups of attributes are supplied as part of the +CUPS-Set-Default Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "printer-uri" (uri):

    +

    The client MUST supply a URI for the specified printer or printer +class.

    +
+

4.12.2 CUPS-Set-Default Response

+

The following groups of attributes are send as part of the +CUPS-Set-Default Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

4.13 CUPS-Get-Devices Operation

+

The CUPS-Get-Devices operation (0x400B) returns all of the supported +device-uri's for the server (CUPS 1.1 and higher).

+

4.13.1 CUPS-Get-Devices Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-Devices Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "device-class" (type1 keyword):

    +

    The client OPTIONALLY supplies a device class keyword to select + which devices are returned.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number of + devices that are returned.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'.

    +
+

4.13.2 CUPS-Get-Devices Response

+

The following groups of attributes are send as part of the +CUPS-Get-Devices Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Device Object Attributes

+
    +

    The set of requested attributes and their current values for each +device.

    +
+

4.14 CUPS-Get-PPDs Operation

+

The CUPS-Get-PPDs operation (0x400C) returns all of the locally +available PPD files on the system (CUPS 1.1 and higher).

+

4.14.1 CUPS-Get-PPDs Request

+

The following groups of attributes are supplied as part of the +CUPS-Get-PPDs Request:

+

Group 1: Operation Attributes

+
    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document.

    +

    "limit" (integer (1:MAX)):

    +

    The client OPTIONALLY supplies this attribute limiting the number of + PPDs that are returned.

    +

    "ppd-make" (text(127)):

    +

    The client OPTIONALLY supplies a printer manufacturer to select + which PPDs are returned.

    +

    "requested-attributes" (1setOf keyword) :

    +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'.

    +
+

4.14.2 CUPS-Get-Classes Response

+

The following groups of attributes are send as part of the +CUPS-Get-Classes Response:

+

Group 1: Operation Attributes

+
    +

    Status Message:

    +

    The standard response status message.

    +

    Natural Language and Character Set:

    +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document.

    +
+

Group 2: Printer Class Object Attributes

+
    +

    The set of requested attributes and their current values for each + printer class.

    +
+

5 Attributes

+

CUPS provides many extension attributes to support multiple devices, +PPD files, standard job filters, printers, and printer classes.

+

5.1 Device Attributes

+

Device attributes are returned by the CUPS-Get-Devices operation and +enumerate all of the available hardware devices and network protocols +that are supported by the server.

+

5.1.1 device-class (type2 keyword)

+

The device-class attribute specifies the class of device and can be +one of the following:

+
    +
  • "file" - a disk file.
  • +
  • "direct" - a parallel or fixed-rate serial data port, currently +used for Centronics, IEEE-1284, and USB printer ports.
  • +
  • "serial" - a variable-rate serial port.
  • +
  • "network" - a network connection, typically via AppSocket, HTTP, +IPP, LPD, or SMB/CIFS protocols.
  • +
+

5.1.2 device-info (text(127))

+

The device-info attribute specifies a human-readable string +describing the device, e.g. "EPP Parallel Port #1".

+

5.1.3 device-make-and-model (text(127))

+

The device-makr-and-model attribute specifies a device +identification string provided by the printer connected to the device. +If the device or printer does not support identification then this +attribute contains the string "unknown".

+

5.1.4 device-uri (uri)

+

The device-uri attribute specifies a unique identifier for the +device. The actual format of the device-uri string depends on the value +of the device-class attribute:

+
    +
  • "file" - The device-uri will be of the form + "file:/path/to/filename".
  • +
  • "direct" - The device-uri will be of the form + "method:/dev/filename", where method may be "parallel" or "usb" in +the current implementation.
  • +
  • "serial" - The device-uri will be of the form + "serial:/dev/filename?baud=value+parity=value+flow=value". The parity +value can be one of "none", "even", or "odd". The flow value can be +one of "none", "soft" (XON/XOFF handshaking), or "hard" (CTS/RTS +handshaking).
  • +

    The URI returned by CUPS-Get-Devices will contain the maximum baud +rate supported by the device and the best type of flow control +available ("soft" or "hard").

    +
  • "network" - The device-uri will be of the form + "method://[username:password@]hostname[:port]/[resource]", where +method may be "http", "ipp", "lpd", "smb", or "socket" in the current +implementation.
  • +

    The URI returned by CUPS-Get-Devices will only contain the method +name followed by two slashes ("method://"). It is up to the client +application to add the appropriate host and other information when +adding a new printer.

    +

    The URI returned by Get-Printer-Attributes and CUPS-Get-Printers +has any username and password information stripped; the information is +still stored and used by the server internally to perform any needed +authentication.

    +
+

5.2 Job Template Attributes

+

5.2.1 banner-end (name(127))

+

(CUPS 1.1 and higher)

+

The banner-end attribute specifies a banner file that is printed +after any files in a job. The reserved value of "none" disables banner +printing. The default value is stored in the banner-end-default +attribute.

+

5.2.2 banner-start (name(127))

+

(CUPS 1.1 and higher)

+

The banner-end attribute specifies a banner file that is printed +before any files in a job. The reserved value of "none" disables banner +printing. The default value is stored in the banner-start-default +attribute.

+

5.2.3 blackplot (boolean)

+

The blackplot attribute specifies whether HP-GL/2 plot files should +be rendered entirely in black ink (blackplot=true) or using the colors +and shades specified in the file (blackplot=false). The default value +is false.

+

5.2.4 brightness (integer(0:200))

+

The brightness attribute specifies the overall brightness of the +printed output in percent. A brightness of 100 is normal, while 200 is +twice as bright and 50 is half as bright. The default value is 100.

+

Brightness is applied to the Cyan, Magenta, Yellow, and Black values +using the function "f(x) = brightness / 100 * x".

+

5.2.5 columns (integer(1:4))

+

The columns attribute specifies the number of columns to generate +when printing text files. The default value is 1.

+

5.2.6 cpi (type2 enum)

+

The cpi attribute specifies the number of characters per inch when +printing text files. Only the values 10, 12, and 17 are currently +supported. The default value is 10.

+

5.2.7 fitplot (boolean)

+

The fitplot attribute specifies whether to scale HP-GL/2 plot files +to fit on the selected media (fitplot=true) or use the physical scale +specified in the plot file (fitplot=false). The default value is false.

+

5.2.8 gamma (integer(1:10000))

+

The gamma attribute specifies the luminance correction for the +output. A value of 1000 specifies no correction, while values of 2000 +and 500 will generate lighter and darker output, respectively. The +default value is 1000.

+

Gamma is applied to the Red, Green, and Blue values (or luminance +for grayscale output) using the function "f(x) = x(1000/gamma) +".

+

5.2.9 hue (integer(-180:180))

+

The hue attribute specifies a color hue rotation when printing image +files. The default value is 0.

+

5.2.10 lpi (type2 enum)

+

The lpi attribute specifies the number of lines per inch when +printing text files. Only the values 6 and 8 are currently supported. +The default value is 6.

+

5.2.11 page-bottom (integer(0:MAX))

+

The page-bottom attribute specifies the bottom margin in points (72 +points equals 1 inch). The default value is the device physical margin.

+

5.2.12 page-left (integer(0:MAX))

+

The page-left attribute specifies the left margin in points (72 +points equals 1 inch). The default value is the device physical margin.

+

5.2.13 page-right (integer(0:MAX))

+

The page-right attribute specifies the right margin in points (72 +points equals 1 inch). The default value is the device physical margin.

+

5.2.14 page-set (type2 keyword)

+

The page-set attribute specifies which pages to print in a file. The +supported keywords are "all", "even", and "odd". The default value is +"all".

+

5.2.15 page-top (integer(0:MAX))

+

The page-top attribute specifies the top margin in points (72 points +equals 1 inch). The default value is the device physical margin.

+

5.2.16 penwidth (integer(0:MAX))

+

The penwidth attribute specifies the default pen width in +micrometers when printing HP-GL/2 plot files. The default value is 1000 +(1 millimeter).

+

5.2.17 ppi (integer(1:MAX))

+

The ppi attribute specifies the resolution of an image file in +pixels per inch. The default value is the resolution included with the +file or 128 if no resolution information is available.

+

5.2.18 prettyprint (boolean)

+

The prettyprint attribute specifies whether text files should be +printed with a shaded header and keyword highlighting +(prettyprint=true) or without additional formatting +(prettyprint=false). The default value is false.

+

5.2.19 saturation (integer(0:200))

+

The saturation attribute specifies the color saturation when +printing image files. A saturation of 100 is normal, while values of 50 +and 200 will be half and twice as colorful, respectively. The default +value is 100.

+

5.2.20 scaling (integer(1:1000))

+

The scaling attribute specifies the scaling of image files with +respect to the selected media. A value of 100 specifies that the image +file should fit 100% of the page, or as much as possible given the +image dimensions. The default value is unspecified.

+

The scaling attribute overrides the ppi attribute if specified.

+

5.2.21 wrap (boolean)

+

The wrap attribute specifies whether long lines should be wrapped +(wrap=true) or not (wrap=false) when printing text files. The default +value is true.

+

5.3 PPD Attributes

+

5.3.1 ppd-natural-language (naturalLanguage)

+

The ppd-natural-language attribute specifies the language encoding +of the PPD file (the LanguageVersion attribute in the PPD file). If the +language is unknown or undefined then "en" (English) is assumed.

+

5.3.2 ppd-make (text(127))

+

The ppd-make attribute specifies the manufacturer of the printer +(the Manufacturer attribute in the PPD file). If the manufacturer is +not specified in the PPD file then an educated guess is made using the +NickName attribute in the PPD file.

+

5.3.3 ppd-make-and-model (text(127))

+

The ppd-make-and-model attribute specifies the manufacturer and +model name of the PPD file (the NickName attribute in the PPD file). If +the make and model is not specified in the PPD file then the ModelName +or ShortNickName attributes are used instead.

+

5.3.4 ppd-name (name(255))

+

The ppd-name attribute specifies the PPD filename on the server +relative to the model directory. The forward slash (/) is used to +delineate directories.

+

5.4 Printer Attributes

+

5.4.1 banner-end-default (name(127))

+

(CUPS 1.1 and higher)

+

The banner-end-default attribute specifies the default banner file +to print after all files in a job. The value "none" specifies that no +banner should be printed.

+

5.4.2 banner-start-default (name(127))

+

(CUPS 1.1 and higher)

+

The banner-start-default attribute specifies the default banner file +to print before all files in a job. The value "none" specifies that no +banner should be printed.

+

5.4.3 banner-supported (1setof name(127))

+

(CUPS 1.1 and higher)

+

The banner-supported attribute specifies the available banner files. +There will always be at least one banner file available called "none".

+

5.4.4 printer-type (type2 enum)

+

The printer-type attribute specifies printer type and capability +bits for the printer or class. The default value is computed from +internal state information and the PPD file for the printer. The +following bits are defined: +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitDescription
0x00000001Is a printer class.
0x00000002Is a remote +destination.
0x00000004Can print in black.
0x00000008Can print in color.
0x00000010Can print on both +sides of the page in hardware.
0x00000020Can staple output.
0x00000040Can do fast copies +in hardware.
0x00000080Can do fast copy +collation in hardware.
0x00000100Can punch output.
0x00000200Can cover output.
0x00000400Can bind output.
0x00000800Can sort output.
0x00001000Can handle media +up to US-Legal/A4.
0x00002000Can handle media +from US-Legal/A4 to ISO-C/A2.
0x00004000Can handle media +larger than ISO-C/A2.
0x00008000Can handle +user-defined media sizes.
0x00010000Is an implicit +(server-generated) class.
+
+

+

5.4.5 printer-type-mask (type2 enum)

+

(CUPS 1.1 and higher)

+

The printer-type-mask attribute is used to choose printers or +classes with the CUPS-Get-Printers and CUPS-Get-Classes operations. The +bits are defined identically to the printer-type attribute and default +to all 1's.

+

5.4.6 requesting-user-name-allowed (1setof +name(127))

+

The requesting-user-name-allowed attribute lists all of the users +that are allowed to access a printer or class. Either this attribute or +the requesting-user-name-denied attribute will be defined, but not +both.

+

The special name "ALLUSERS" is reserved to indicate that all users +allowed.

+

5.4.7 requesting-user-name-denied (1setof name(127)) +

+

The requesting-user-name-denied attribute lists all of the users +that are not allowed to access a printer or class. Either this +attribute or the requesting-user-name-allowed attribute will be +defined, but not both.

+

The special name "ALLUSERS" is reserved to indicate that all users +denied.

+

5.5 Printer Class Attributes

+

5.5.1 member-names (1setof name(127))

+

The member-names attribute specifies each of the printer-name +attributes of the member printers and classes. Each name corresponds to +the same element of the member-uris attribute.

+

5.5.2 member-uris (1setof uri)

+

The member-uris attribute specifies each of the printer-uri +attributes of the member printers and classes. Each URI corresponds to +the same element of the member-names attribute.

+ + diff --git a/doc/ipp.pdf b/doc/ipp.pdf new file mode 100644 index 0000000000..209c399c2a --- /dev/null +++ b/doc/ipp.pdf @@ -0,0 +1,1329 @@ +%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[9 0 R +10 0 R +11 0 R +12 0 R +13 0 R +]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[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 +]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[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[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 +]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<>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<>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<>stream +xÚìÏsë8rÇIŠºÌ‰öŒî´üt§çyšÝ­ÚJñÙfvçÖ$ÁÊ!•S*Ç6•üÿ±~X"H€èn$è5¦jêÙE|ˆÆ·@ƒúÇOßòýÛßò?=å¿ýžÿçÿô,~*ÅOÿÈÛÿù×?þøÛï¿ÿºÏÿü—_Ÿò§§§·kýñõ¥ù÷¯|­ÿöœþº?•ßNå÷SùË©¼œÊ¿žÊ¿üÇ×?òÿýŸÿû¯¯ÿ–ÿíÛ׿ç‡oß¾>ÃKþ=ÿãõ§öcøä²+âõi»Ý>ÜËÛ?¶ß_—Î%^¶wY¤*w÷¯ËäOj¤Üöû¸ē‰é½Ü?–KáÂC]о/ëå!"—x[ÎõœE¼r˜ë‰KåÒ!˜¾rÛg޹^òȾü\ÆÕÊÏ3s=GžJRÎÉõ-òVâÃl\ŽuЄõV¾ÌÂ%²( + ‚B¹ü29×$X,0X –€Åƒ %ƒ/° ¬(ÚMÄåÝoÙ9h6×ÄXo`å\ûhò’LÀõ#𡬼sÕÑ,åÏ\M6A!|…gi,A +Ú Ñ ê£s5Ѭåà‹+›— 9Ä`™ãÅ`ž‹,öD.1?V{àÊàŠRç\uD98æY\‰c®}HÙ8媣`Jé++D91WT蚐°ŒÒË TÔ  LÔ‹Š4ðZåªBÃ2t,OãQ ÔxŒsÆq‰±FãzX¢Æ#F,Ï%£FL×]w÷Ûí—×cy>|ðÛa0IwÅ÷_†ƒüxÂ[‡ÿîŠG’þÅ˃ŸßÝuoœ*=[ í,¸ö~ºªÛk[ça=xì.Bú±àæØ\ìPƒ–.Î$[q¹¸¡==·aMJ&³»XéԜ.K™\¬@ž› É貘ÇUùÑv‡]¶cqeSÙà՛eN¤ܯjؤ½s’  ®|²¡ÅϼJé\Í Xd°˜ÎEùØÍÉÜZ9ƹfÂ"‚­¨\Õ FÈ1ŒȕυEÛи'’ –Y¹0p7ñú¥uZj+Cg‘¼c,Òé« …«rÎX•½ÅÍÁ‘jÄ¥{.B J<—°ÒlKÃ7D=Ì:¸ÎåÛÁÉ %i=•œkˆàBf½ .Ú`Ø`¹Š¹2O”,Á W­Ç’ó ìÍПR4q‡ãÚa…„–¤8®´&1Š«žÙ#3ì€á«aÚz/8 [c¸²0Dƒ¢õ ‚«æfóuXiæ*B J‡íÌ\Y OjOjäªÃê.d‡%F®"°îBú°ÒĕÖ]È'½1p5Á¸dZ“RW\wá¢ÄÄÀ•6ºÐRVŽr‰» 7æw£\u€Ý…[FJG¹*OŠ…²¢d”+ (2$*ÇVå'ÆB ÃRåÓ©¹Z’ Wå“s! q5ÂÀÚÛ=W¢È£­ÔrAˆ"v@;-W¨jàLi­ã¡ªnè¯t\5-4”=Ùí§ž±¿ÿ.Ï´’T¹Æúù=¾aÀ +¢6(®–KH·Kh%ºÖRÕÓbQ®•–ër›®Îa‡Àà ¯Çé¹ £^ >ÜÌіœáµCrí´\MçùÖ 1£$UsÑys¥Z®³í%·NH)}¢æÊ‰Îkœ+ÑsÝ´BPf=ègŒàp‡åz7.×MÛk¼b”¾Tq5ÔÊÀµÑrÝD° ¬•T؇ô¹WŠçZ鹊÷G”Q&ß V<זByW¤çª/ŸÕPÌ1PRWF4C#×NËu¾×úü+ü’QØV +.A5C#WªçڟòáªÕr[¬àª©fhäŠõ\盽§5Rì•K,×êZ[Éu6Ž;êÊ12BªWNZ,×:{—'%WG¤(³ÔgO@• ž«x j®Š5K5†ˆëWC6Ãq®ZÂp ÖbI…Ó5 ÊFÒâ¹Ä»Y¨¹®&EZ,ip-â\9%pžê¹*֚Nè(; +\n£á¬5;c+\ŒôÅq®æ" +®K‰kvª‰@“¤¥pµ¥×qgéB™ÐdcMãº(½Ž«àôWòD@“ë¢ô:®Œ3¾êÙwCÅuQz WÍÛÃÈ0’ ¤h#!r]”^ÃUðûMÏ%s Æð2r•^Õñ6g +ÌÃ’lì¨\g¥Ws5Ì]Œ +㘁´¶ÑR¹ÎJ¯æ½ØER2WÁ^f®“Ò«¹rfæŽÀ8f DQ)ëd݅~^¹e¢IàkSYŽ­\§Öç*®³Ý Fȑ#š ”(ªT?º²k ±ÌukDŸ+?krN7Ä="àVÌµë>š>h¸Þ;а›‚]†Yw¹k6+IlºŠšô¸ Wuáiè†X!dr¸Ñ˜ÄjøCýsȵèÝJ´§•¸rŽlH[âã‹:\…’K\[°'¢@Ø¢C­I¤€]Ÿ«VrU×Ê=öEèà£ÃDïû¯´ùÖṌŸêsí¯#èùVž«áxåÛ-â;^WÈ\OÌɱonn0¾d=äª\ÝT”‚lˆ{ó€¼0ÚT¹WWojò$ ð\{–l lbÕ¹.¶*qeÝKž„‰×ñÒáÊY²Ñ˜×Ó{Šyq—KΈÚ{ÈhzªX¯üPy8Å:F—« »òúh9ÔNþnï5ùÒ*¹Ä€+“,¯ñª è¨Wo'ÍéŧñýGH©\SßËy°†ÇeŽæãvQ°2Ÿ,’+çEQÁse¼(*t.a#‡s5–r*W͍çª>š^¸ +vt6מ͕4™¿peM/\œ¥ùp‰'óg®úÃÉ<–k2ߝÎ-‡͋ó·•Ü:\[æ»uîªßFwÒ²ßmµwpœOm›.Ò,²Î-ï\·u›þà,•\×FÍÕI¿\¹r¶ûRãkT§×ćk¥äjÔûËÛ}©4fÜkbÄኔ\¹z߁¿h£¶W]nj¯‰;×NÁU UPn9Ár­4áËNŕr¸RW6|ŒŽ¹Î«Ëë51áp%C®wшﲫÝÊ-§h®š+Vqõó¡¸g¯r~ô'/ÙÅlp\ëQ®Ó¿^òHjÁZv,¥Šk£tEr<Џ¨ëdÞ7ÛnlÌ\—᯻?"éx@·‰+×à¢Zr—Ûj{‡àꤥÈ]|Ëíé71âp .’7.y<€ +£®[‘"K~­lâŽÃÕ¿(—óM +-áðì8—Ðpz®”ÃÕ¿¨7RNf™*Œj1\·Ùÿj®˜ÃÕ»¨ðTà¹b\Šã|f.ÅEußÁnßÊ#`ÂÃĞk¨Šã|f.ÝÀT5_ŽÜp ×^­óŠã|®áE…ÒÁ&ŒJ[=Ì®9·r‡Çù\Ër¥#Bq­Q\µÚ՚8JqœÁ5¼HËU;â*”ñÆË- é5qxœÁ5¼(S:"×Ã%¢"ÎSÇù0\ƒ‹´\?Œê´áò;ô¼RqœÃ5¸¨[ývGסµœm”MçÃp .Òr?ŒjÕ£YU4ñ"Ú4®þE\-š+Uý6.5MìçCqõ/Òr¹ê^,ÕMìçCqõ/Òríùáa«68Íòþ ‰ýã|(®þEY/Mõʕ;ãŠK W'T•šØ;·ãê]ÄçJ\ñ®óۋ_¾,{lÔMìçÃqõ.Ê;Š-qen¸:ù‡Ýxã¼ì‘ª›Ø;·ãê]4ˆ£*,WÚâæ)­Š«ó~(EO¢Må’/Ú÷#¢âÂùåªÇ¸äã|H.ÅÀn÷X®µW£‹ç¯AeNä’/ªúC%;s Ï\BsŠCqœÉ%_T÷$[DX®W;Ê.é"Ñ Í« ¸—|Q&°üÂeÎ=Üy䒎óa¹ä‹ +E2þW=/WÁá’.ªn»Ê·EÞÙ¹j—t‘è¶²¾Æ6ÓJ\‚Ã%_”ßö¿ž#W铫{œÍ%_T ö+Càª8\òE½H0?qÙL—Q\Ù8WÃá’/’gÆé>®Îq>ès¥”ºór=ŸÞa?bšK©;3×Cÿøšü²¡ÎæuÕ»ꝪHqPJÛ:k®|¾!çéw·§†u\y1Ô׏áŒF~™WsÛìø9QeäÚÉÔ—Pì(É/4¬®KüuòÈȵ™‚ TSë¼;Àz齺 ®u+ M?\™j« ºã “Òdúu\©l)^¸š÷§»nÝî«ko»õʺ ®Dºµ®êºQ(¾unڑÀ[v…².Ÿ«öÉUtv¬÷7ïÒqY·äsM]Õ2¿ú®òöNå“+ª›v^Ȭ©K㊯ۧoƒ8ñƕu—áòžÒߌ§©KãJ®£0qÙÄóҟá¦×VËIÚªº$®Õõq¼=™t®êöÓ5ä$mU]WÚ}tk;.CúáõÏÍÝ[ÙtĪ윑Ò×%qÏ]ÓÆ+W¢ûѧ“T<¶ÔçÊ/ƒô8„wÞ¸2]:ÎeO¹éÀd#©;x®ýåóŽŸ|ðÆuŽš¸1‘†‘¶.‰«¸ÈÐÑÒKo\—½Îûƒ:À:eR¼Ë¹¶.‰ nÙ¯qëë¢Z{þ⇬ã‹õu•\ÃÄÎEu¯G÷叫“Òkmñîm®¾X_—ÂU_ `ü`;®±}½n=é½ÄÕ0‹V[—ÂÕ\~<ºeK®±}ØByŽCš—ƺ.]_ˆ¾ç²Ú_ÚÌÒ|Õ¢¯Kàj/Žùô[\½,Ú¸ôdЍKá:;æ“[öÉÕyіL¡ú’9]] +×Ù1×'ï“ëý ì —J•l:ZÇuvÌõ©¾—1ïë9Sš\ùPÔuñ~ùäËãÿc—‹|¶—‡á¤¦ÒLrTu \ÕÉOnÙ?×­µ«^(u@Õ%póÉ-OÁõ. +‰vЌÕ%póÉ-[raß-Z‹ÁX]—x÷b멸n‰×f®^]×Ù1ŸEr”Ë&ûø*™ìе\cu)\o&˜4·õS/\²{ãb§®.…ëM2âúì-¹JÜú¡k¬.…ëØÓUt}Q7®D²­x”KW—Âçð±‰ËæÜM.ý9Õù±º®ê|²&±çڍO¿6ÝyÈJË5V—ÂUߜº7®ªÛŸûÞmz«Kájn³Q.›sˆçkãï·M­–k¬®!ž—Þ¶%ä]A ®qö¶ ©Ÿ,ŽÕ¥puÞ ë«™«õ¹F꒸r—Õ¹ìf¤jŸk¤.ƒ«´çZãÒmú¡ÿ VÑ×%qƒßxàjô +3àj¸ëQ2\ŸÊ(—Õû7䵘_ÚQ.}]—îý¬n¹:}l \Úº$®úêÓǹ¬²Þè!Ón”ØÔµ*–ïí¹Ê×ëMóU|–ïY +¶X¾ë“kz.ó떗ÉUüÓr•‹ä2/pÉe3aþ䚞Ëjb¹h®õ"¹Ä?-WºH.ólõA¹’ere0ðµü>ŽO®¸ö0ðÅ}Ïn‘\ðA¹ª Z~¯Ù\Åô²×å÷ÐÍULMÞá¾70¸@ªrÃ\ e’ºÒò{9ç*Š+[\Àa +%°ß{ZÀ‘›ì ù=Å¡­´e&=@~¯thG„â‚¥Âèo‘ßoXÀQã¸÷}ô•±mç˜Á8lc®Á9æ½Qæ#/Á9°Üè–ã‚s`™±Åš3‡}€²×ÀXcV@éK`3Ëڬހò9°ÊÜX@=€ÀXa6.@l`3°½9êT˜ËÍ"8á Kèmœ£ Jè„m®gƒú¡€S˜ „A:àª%ô¢©€ìڐ„>G˜ ‡bH}fv_ï\bAB/0Ò -Vè׋‘Ã]‡+_Ž V˜Ȑ+ A,0 +-V裥ÈaÜ媗#ˆ(Â-ôDˆ *âƒ-ôéBäpÝåB} Â(»‚-ôÇ¥€VÏP„#C̾:\ÕB")£œ· Å }ºÙHd.„Ð'‹TæB,Ýċu+_†pd8üƒ"âȇxà B8j¤—Â!Gl#´A `1Û¨«>BðÌØå +h)‚¸xí\Åú,(ÖCéÑg­¡% ÇÜ ýŽhIÂ1ó3?ú•‚+~€áï€d¼s°=z @KŽy>r’s˜y€Õø©bå™a÷H*:sˆH؇–(30Ê&ÐúyÖ9eˆιÈQDs‘ƒ²Ôā9£Ò7”AОQéI+Ò@½t>¥Ï)Mª’ζÚ&HšÔ¡9›!"li¥åڇkˆ´åhél¨vc! »ô™ ±¢g83âžö¼nų¢ †®@žâÌcˆñqCË`3Ĉ9qx@Ë`iˆf(Í4€ó`¦Ÿ¬Tԇ -g€M>kΩj-k€MœdY“½´¬6± +ÈcX]>±rz‹€5D'VFÔ +œéöÔ1GNÀY™8樼A:©ÔgB©œÇ Üϙ.H,8ޏÃtºc wàÊêd†kÍÁ…Tú‰:,c=càÔ4Æ €?R§é°ŒÖÛNÓaә_‚& :C¢Åqí±`»0ºk…äªé0‘qƒph­ ±÷UKó„ªY.´v†èuâ,øV­!zÕzìÓÝ ¹ð†èQ:j ›ÖÖãrfWŠØ ¬OKüñÍPË%¢¹-±±’.h­ ѓ&æV>¬­'BõÊXZ?Þ¹±´°öõ^†˜È,e \<1÷3–½í#×½{&ܸ¥rU¤s©ÍJÉ\"š LdöܹK0‘;¸)82‡i\o\´;¼•Ÿ'–‘P¬.t¬Â^¿¹1p1_uFÃÒÇàd}¡ãNSbé¥ +\EiW°/)áøf08Ô&[õ cœFwžÿf<[l2êR6W›qÀúßtŽ*OôÛø\‹+Š¿S;‹añcq€‰‹ÙaQt_zî¬ñ¹‘‘«ˆ¸ÿ¥ó/9k·6\"â—{”56¼OßYqYtØqœ=šÌñ…Ie˜>˜¹l:ìŒöªÿ짌ý¹K.ê4Li¯ƒ~/ÛÌæqµ¶\Mä¦ÜÝo·Û/¯oåe»}È,?mcÍå¢ÃœSþ#†KȵqÀe'‰³tŽ+¼Û9á +®ÃÌK_8.±´îBrvm¦(ˆ=$W›…ÄupÇU/«»Ð\¬•O_ºäj‚áÚ´.¹‚ÑzÜöžKdKÑxw gÑ q!Øý^ +—XŒÒ¸°DôÖ!‰kvKÄgиš…X!•kæø—°MäšÕ)¹/T®9½3eû‰Ê5c`OJš#sÍ6Ähi/t®™†1±ŒÁ5Ï#îí2¸fbÔ,%=pÍ`sM®ôT9×ÄÚÁÈdr‰<\)´ášRY©Ã\®éÀx™dl.FÚÏ$ŽËšk¢Éóā×þ9椰áòoŠü,M+.ß`ɧv\~UÑ&Yؒ˧ƒ¶Ê¶åòf—ŒoÍEΡö41qÏåcÚb™®î†Ë½,ڟ›pÂÕ +·¶øhß"7\o¶è®Ë’CW+Âé,—\ŽºìþІÆÕŠ'küâª-.¹ø©ÕªGw-qËe‘^Hݞ“‹Kæ–ʇìþ‹ë6øà"æÅÇ[ï¹ðÃõV^qÙññýw/·÷Æuê5ƒAÞm_}ÝÛ'ש۞¶wê~z|õy_ß\çŽ;žpØ>ÜËývûøúêý–“pÍPàÿÿÿârõä +äÿÿMÌA‚0…á=§˜¥&¶v +»Tƒ » +õDŠb€’¶j¸½TcâvÞÿÍ^Eë£Î@5€,¥bA· êÅá,KÈû±Ó½|å[3€i —r©î³Jñ«Ø Ɣÿ™#‚CH0 3ßÐ$ÌYå&(Mã_•Õ ­©ï>aÓÍß3N¶½Þ< )ጱ캊ptPh§íSׁf*:Eo/€î­endstream +endobj +223 0 obj +6279 +endobj +224 0 obj<>>>endobj +225 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +226 0 obj +31 +endobj +227 0 obj<>>>/Annots 14 0 R>>endobj +228 0 obj<>stream +xÚµ•;oÛ0€wÿŠC¦d°*ÒÔÃݒ´ ¼´n¬¼¸å°EWb¤¿¾Ç‡,iT "øÝñ>MýšñG ¡°ˆ!—³«löîÓhY‰3q +Î lruàÙO;K7;I@í|@`UðZ‹Rä;-TíP„x”ƁM•Ý‹ +•?HÄáШ£(x »ԑ7GÁA• ï9¬j͛škX73×{|QZ媂íùÙj½>Û^Æ´¸˜ +v-y¨¸ÉÌ ¶\š,\•&鵒ñ»Ï«ï}ÞÍS«¹4Y¯ïÖ“ö[Ÿ6xfÍ uÖ>t&_|õÅñ]5û]-~ÛJµ²Ê¥ª*õhJjyn¶±}ïòå>MqÍSÊ-0ÀÇl!¶Ò<ˆyÜÞ`CƒX’1H` Ý ‚Í?è !Zü‡Ò7¿§¯žÓì¡ß¢Èvöv0fïi'7B Ë{ØÓä#/°@ùáßåuÕK|vêv0¦îig6BÓxD|‚; Mý̘xc¯È7h;0¢s·ƒ1wO;µz`ۓ¿è êx[Ùë2BùK­ñãA¿Å™'ÔÝtqøÁ ò=€ò‘9Å#ô@y†Eõôy°7Ý%ÊßTªmwÍÓKêi§ŽóSäàÛËð¦]‚=IÄoÆ×ÙíÃãendstream +endobj +229 0 obj +578 +endobj +230 0 obj<>>>>>endobj +231 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS047Ò3S072PIÑp VðÌ-ÈIÍMÍ+I,ÉÌÏSÈOSð Ð Éâ҅¨Õ…*6‰™˜˜…À|C…àäü‚T¨kW þúendstream +endobj +232 0 obj +108 +endobj +233 0 obj<>>>>>endobj +234 0 obj<>stream +xÚ­–Moâ0†ïüŠ9v%HI r£PZVE͒´§½g^%6k;jù÷µ>ʖJZqçyçãQþ6|h›½:!Тq“4.'×´!É̝°×…$½`ŽJäՏä;â÷ª#­Ð÷wÈóaôÅ0´,k¢™àÕñ.øþöxzŽ™¬2‘çâ…ñeõ`úþA` +äN5…ÅôÊ\ڝT`º}Ğý;{p¬|aZ£YÔò=PéÏز”•ÞŒp²Dˆ('ü˜o÷;UžŸÂ§ãñ;x¼Q ˜r2#aŒŠ-¹ý¢’­µ©#gVÂ{݉ˆL¿‰0L ƙÒ&!•Í¥$ùüãvôo =šBGR,%) +k‚³£Žç§Ð1ÒR2½1æ] ©Ïà&Ñ)n‚ê\‹ÄOŸôïIáWÚö<>}6TëíÛÍo«œnÛëW3À£^¡Ü±úÏ悷ކX à;'x˜Š…1ŒP:vÉï0;]ﳃ Ë&BDC¼FÊ2FÝ|7÷Åèz¯V??¾,Ͳ8¬Å&$+&S¸M™«ÇŸFÑ~Šžî“ŠQÃã«å¤êò.oo9©íŽ'’pU{ö¬i±ÎÝv´F½+YŠçqf"ÅÜcA¸f´^róÉÈüì]7áq>>>>>endobj +237 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS047Ò3S072PIÑp VðÌ-ÈIÍMÍ+I,ÉÌÏSÈOSð Ð Éâ҅¨Õ…*6‰™…À|#… Ô´Ô¢Ô¼äÔb”kW ¡õþendstream +endobj +238 0 obj +113 +endobj +239 0 obj<>>>>>endobj +240 0 obj<>stream +xÚ¥˜Ûnã6†ïó߸bY”%ÙÎݞºÈ¢hÒµÓ{Y¢c.$Q%édóö%ùØ¡·ØÔ?§œ“¯„øÃ`Á$…¼ºú¸¼ÿ1‡(„埤ӖÅo¸{âêIðçߗ?PcN0ŠÒ€$ŸîÀ¢jJ^ñÚh¸½¿Û¥¬.Àl8Ȇ«ÌYkZʌQbµ5\CÁע戚„´¼orEº{%jÃ,¸±á1(›‘ z×;\“‘ ww[ÓlÍh…Þ>t1àËOÃkZ”Z¯;9†z#êG õ,‹áõЪ:áp••|x¹Ïž²r‹ðÞ=è†çb-r—YÐZ€ÊJ-¡QòIhË"¨ùó1ž*«_h}“‘ ·M#•j[¨-etEˆœaûå(ã¼Ì´F²† 4V‹¦©Mà¶tlÚni3ÚuÜ:ëüáû­>¿ïmNVÒlÜnŒi´hðSÅÍFPg×,Q‚¨KùŒ‰€âZnUÎÝSȇ­æÅ š¶Añ€öQ·›ñØV`­nlüña–Ö «þSVÃʹÅÀ +7 „Á#7ƒ=êÁa¼Ñ¾ý‰€YQ‰útԇýp¤ÚØhOüÿÅm7slWN‡_¸ƒh‘v‡Èò"þ+=…_0ÿBˆî_^áëÈBâSóÒ`–}íxáYnËÂ{,1…µ”Á*SA.«]fš«ox:Ž›÷›§(„ݶk:çîøãläÊ5uß +µTÆ^)ù¬íÃ<çšxpî,×G};xçØÉwnϺq÷ôævÚüne¼ïS"¶ú¶ðâýYÒå˹i9Zv¤ì÷ùÁ²?"û »?(ÅnC,Û +k¹vÉL=S´U(þˆíÇödïë¨âçvø$mbi$˜ÛÔåÖ§µG•…a0ÁôÛÄíR¬]‘‰æ £ÐÊG%ø>s+ј6/Ë«0ñ…ÜÿúþâY0E˜)Z2¡Ç(ď8!oˆYja;õd¤çÅó9ÖäÄq‚ÙŸGXMç™Í'h¸Sӝ¡ÛÁ„Ù|S¢I/î¾Æ‰eOÕ³ ´+”!-„?Ã0ŒZÒa$clâµ(yðž$ B<¤öÅCb_<.×x”˜¹Nø'+E‘îM&>$ÓÙÛ1»w9xÒ$±)úB"µ/$ûBryœ‚1 i{FñSˆØˆ’CDκ{Aôï£3tX¤þtHíK‡Ä¾t\§è„¬}½ñº}–ùÖ^´½¥‡€¬ƒ¶¹ÜśÔ< boP$öäDZOL.‰”f¬¿óå¼ôî²ÙÑ"ë ÀL“ f4‰=ÁÖŒK☔پršÉ£þO#í…g~ˆ½\6’ä‚MbO<¤õÄã’8§»©´€ü°|xÅ^öíÕë “ø‚yLbO ¤õâ’xë…>ë¯dáëij0˜»I[åßWÿ²ª<îendstream +endobj +241 0 obj +1120 +endobj +242 0 obj<>>>>>endobj +243 0 obj<>stream +xÚ­˜ÝrÚ0…ïy +]¶8úµÍeMšÞ”ú‹ÄƒSchûö•´ÿ«L'™dFs´£=Zó«Ç5?ŒˆØþΗ½»iïæ^ÆÈtA‹§"JÉ4ÿô ›þ¸.V®û·MS³M£×Ÿ§¯=Æxd+‹¨]iÃýC)½³kREÖL%ò•H¶«YїiFԘÚýyz 2µ>’Äø€â4â¤ÖdrAÌbjt v6®ŠƒHµbçK¹«ÌÂlÜ« 7  ó‘æ¿VeÞÿVÍÎø° |†Ç|ì^’‘×jFU ¨ŠÕs •˜¢h@NäÄX@àÃHŠHڇ|Ò¥ÎÖÍht̨ÝþL"‰$“Sc191øðaâÂ,™çg©í;L³1z ÊØÁ!ÕÊ k›¯‹KŒ4)§Æ’rb,)ðá#Eœ‡õfŠž([áC¤Ô ‰(š¨‘¤@Œ$ÕúðR)‡$oêg×x¨ôfüä@ÙÝ$+KÛy]©­’8 µA%ãÄX2àÃG&æÚsÇ.×î· ÙÄä1!Såà^sádN’^åîXÕäE›|7ðºØ©8 ÐAeçÄXvàÃÇNrôáÏñ¤o‡„‘^d›²é>[Ò ;Ÿ šMr(aþ¯M/fMQ­º`‰8 ÖA…åÄXXàËsˆõ¬6°Ö(Züœ–íÃjá eÛ¬(³Y©ßS«³9Yð Æ2sb,3ðácF÷Änóñ˜8f¶Ûþ[Vy±ø‹Nw9ˆÒÔHL Fbj}x0ɔAº;P#35:ˆÕIˆA<¤D=¨±œ |ø Å ‚~×Ã2[¯5®ýTXû‘9Ôî"§T@̃KΉ±äÀ‡œd1oûБCq‹Q]¸º` ó ÆÂrb,,ðáƒÅÙAÌ·½ˆç•\ïD(¦²ÔXPNŒ>| (۟©ù\¿5ȱÔPJON•Ûîfңѝ¼¿"Á‰ +H{P#Á ®õá'RzöOúUÏÐ Nß|ìöÿ€.‘w¨±è‰¿Z>tæÓ÷wÀ$p`½=õ?6° +%bÔXXNŒ…>|°$=›î·Åó^$/~ïwñÂÌ¡f1!²ÔXbNŒ%>|ÄÜÒш?áp ‘¸lÁ.VLÄ?¨±¬œË +|œ³º¹OÛo™Yb_¾Nß¡‘Çå[©—zÕ¸>²Ïÿ8Ûç탶ߊa®p ò}«ëm¡·h~ôþ½#'endstream +endobj +244 0 obj +958 +endobj +245 0 obj<>>>>>endobj +246 0 obj<>stream +xÚÝUÁn›@½û+Fœl©À–ä–FMå*©Ý˜*qY`0Dx—,KRÿ}g—µ±Èªzªª¬h‡7oÞ{;û2À§¿f!Œ§nŸ£ÁÅÝ„>D9Lgˆ²á5J¦JÁ›QôL%‚®Ä §ž)Š +„\T•x+ùLM9dؤ²L‹= 4m] ©0ƒd ·O˕snŠJ®Pb£@äH|-ÕöÓÁ—šµ Æ^¨Û¾eZ@Û8¯¶ QŒgLf0_.)Eí[… 0‰À…ÚSʼn˜+fv˜‰ï]š‰½–’˜¸ßDÒOvø¾~Oâ¡ÿË÷ý0A­‰äe…}ç‰E½©í|Ôû_Zãe_KÑ֍Vîdn-wU’Ú¬šI#®:"m][}wø_5"×½p³‡Öµœ}ñw¦ZÉ*¸g|ݲ5·“,%Oa…ïà5}§çê¦TÜ r̗‡¼ƒv+ íMØç,£üìÒc“=‰Œ]§ãAdX™^+Ü0®Ê”DÚn+cDé¶²tÈYú‰G͓’Ð\ÁÃÓ*êtߒëOsòIv­1-s톅4­ÜC%;ÙÃkÐÖD¸©+¦ðŒòNÂ8'nÈ3͍³ ÆÃ œÅ#Ëñânú><ñPß<ЉÓåº@Î†ÍN·XFóÅ÷›ûûŸ»lélw,(ak}ᙂ²±3RòrÆ·æ4Ú'-†9†g‘x@ð'Vé9tT.8YNh´P¾œ„•©ÖÅ´ââ¨}Sˆ¶¢í‚;´`:ãí™ ´NZvæèMBÝöÓv|_YÕâîúÈîf˜³¶¢èZSA$ϔà ¤E•½ –¡½%Õ¿ê^‚”^üOí3Êÿ½ ’çnêÑՎ>Z»º[ã݋Ø=Z¥:g/{gg}4NèÉ¥ï]QÍôÿ_¢ÁÁo…¥”endstream +endobj +247 0 obj +728 +endobj +248 0 obj<>>>>>endobj +249 0 obj<>stream +xÚ͕MoÚ@†ïüŠ'jÇk¨!¹¥QSQåƒçPɗŃ#³ë쮓òï;koˆ)9äRÄÇμóñ>¶{ z1EönzßâÞÉå)°1Ä9DSæ‡gƒ±o¿ÌU!Œ÷S.áu%…Æaü@ c`¬MðÂÈۄxË²”Ï…XÁJÉºÒ sàÆ¨bYÔÀ‚F‘×Pqe챡´Ã*g¶LGü‡•v·*n +)à|§kci˜]ðÂpSk¸F­ùê@Êö© W(WÏþcs6mŽ¿—sC‡Š—pÅŪ¦s t¸XsÅSƒ +hÞ«ÒÝK)X£é7™ÝÑJ{¥“î¿Y˜† uJ?1ƒBÐòÒfö™3öCW“ZËÜ6gó9\Ë Ë¦Ö7\˜"%%™Ö¦Îë.¬Ýnxւ£{m·vÖ 4±D4ÂãÀŸ¶…p¡lÜݙw¢N‚ܹ ‚?A|M†6ç´øüpS™-T!xK׎#ڍüÈ5ã³®ú>֨ͧ‰®«ª,ð€êÃJŸ¢úÿd}‚ÁN«ýÆ?T^­Š>™MÉð½yRÚ4}}¿ˆÛÅo‰ƒû»¥šÊºÂ´È­NòÜcâ§$ŸŽl¾¿äBPotç²½ ¾ÁdÀÂI2t=ž\F‡ô$ƒ‹ûù1gw°.VkTÉð(mnºÛy<»½9¿ºúý—¥½í‚#ï͚(´›‘ÐË-\l!/JŠ&Ÿì2^¯ + ù=«ì–Õ¾‚,'5º¢z"9#I!+R»—¦”oÊëµ¬Ë –øÒ€³Öx7A&© !Í^É֜-ERµc6±í÷‰—5¾\?µ{æ¼. ]g*ÈåqØÑ ÁZS#û`9º¿+ó/÷¦Î 6ŠèV6™{3‚-°íÕIÙ PlR¬7 >>>>>endobj +252 0 obj<>stream +xÚÍUMo›@½ûWŒ8%R¡€¶sKÓ¹Jj×&‡J¾,0ØDx—ì.ióï;8v'=äRù`±Ì̛yï1{?À§_£†1dÛÁ§dðñk AIÁGñ8òƐäg«³«Ûù/!sؔë êÕùyrG QŸàƒÆ^ÄñÉ!«J”fód:ûqy}ý LS×th@@*¤D µX#؍°P¨u)-æb¡4Ð#eEᥤìÞÝJ= úŒMˆÁÐ QŠ-‚*À‘J¢Ãå4ÔTÏ*ª—™°=–TÏðÍF5Ãî:ð`Z´ˆý¹¢&¤²G¦Æ¬,)’ЄµºL›»~DÕ´=ñƒÓ!ºÆ +mÝ ÑTÖé5¨ô3{P…J6†Zé1wÄ.-ñ/tßU + n늧ºÜ¥™N‘ +⒆îpèŜy!õ}¥‘2\N_ ©•4ø¦Š…ª*õ»”kXkÕԆçyê’Æ&¡ ’%éG“íÆ=sq4Ê7®ÁÌjÔ–JÍÁÍÌm7h Iv\Š5;ftÇ'œ³írŽ™üA/µ¨àZÈuÃ6`c_m„ ²D{ +ÅÙÏîflDäÌò+íV}içcr4=’5Éنtçه^à‘DGëéœÎçp£r¬Z¬%n…´eF•TÖlÉ¢ípî!a»áEk”7yÝû鄍FO6ŠünDސÉaiÝ}Â^Ä7Ýt"Q=©¿:óÿø¾®Î»Ï‚÷/﹩ýCKk§Š.ð¾Acßíìna½p÷ëˆï2ùÿiÉà–>>>>>endobj +255 0 obj<>stream +xÚÝVMoâH½ó+Jœˆ4v00$“[f6ŒX%!œÃH\»Œ;kw{»Û‰2¿~«º 2ö´„ ëãõ{ÏUüÓK`H¯ÆS~guïsÚ;M I -èdz>‰Ï!Í_n]ÀŸz )ÖM%Â¥sF®[‡ö$}ìQ…h4'ßÔë¨1R94QkdVúX\päp˜–Y%Q9XÜ¥óÅíåõõ7°mÓЏ?ÜÏA @á3t5!Gë¤Nj…6>zÆÀ9²ºVÉ8q«›‡e +­“•üŽ>ފa~wÍÕ\ dŒ1¼è2¡”vPë'ܖ§ C.‹ à I«“˜ÛœÎ>îHÛÝív‘^]„Ó-¥Â'-ˆ-q@_r,¤Âœë¯î¯.ÿˆ·D‚T¾uÖßo~•ÎÀ6˜ÉBf¯/.íÑEuƒÆÄðåán ¢ªôsàò­.{(¡V +µÁü<—2+¡w2p©£F’|€5 p”VQ¦¡ª¥ÚìÐA#Œ“Y[ {hG>诉q„*g¯(’f5HFg«“Î3§³é[†WÁ$N@¨J¹)Y’CÎÝm +B¼a݅c}]9ˆ‚'Ô ²¢èN¼óÞC|6oŸ¸Á>W3èãå–*g)»VJ´·¥n«œ%éÄ0/‚# rM È¥G-ƒE^õ¯Ô-1à}Uë1y?ìiÈ‡¢­\÷Œéõ#fîЬ­% ?ÑÎ:úÿªÞɏø›Êç™ÿï.¨–yo´ŸÎ>A2a9"žòãq<å¼IÌ —è"ʍö)p¶ÑÊâ»RšçOŠ oë‡ü¾† µ,ùD˜ Û;¿Óîx¹„­•\Àb;vÞYYKšb­…´–ôûў"–U.LÎ&ðýøΩCÎ1­·thD×4Q[ö»üK)ŒÈXºÈºô÷D4ŒER”3_¨P:ªºÒýæx§ØŒ¾’OÉæ–LÀwÇI<‰GÇÛ"ÐÊ{ðFçXù^K¬…¢¡M•tÖòˆïÖÜy§e2ž’>~š†ÿþAž®*LE9-JÎF†œ =÷` Ã_öÑUÚû«÷/7`Íendstream +endobj +256 0 obj +832 +endobj +257 0 obj<>>>>>endobj +258 0 obj<>stream +xÚÍUÁRÛ0½ç+vrfj;nL¹QÚ2™’sè Ŗƒ-I&äﻒÛ8†——íê½}û^ô<ð`„„>Œ'ƒïÑàô×7ðBˆR<™„¡;(9Ü.ïç çŠ*çMI•+˜•T•qv=b[žgÛ‚õØ­é~ßµÁÃñè5¼‡TU‚IPؑԅ¥È˜¢îï¦@XD)‘-+E¥k‘hP#ŽÇ Q×ÛǼ£Ï•ê]¢)Ïs¾ÉØ +V‚W¥žv  +²*Ë<£HEBI„Ò%êЌ5Þ¹ìÀ\é‹Á;o¥ƒ‹A×âšâ[‚’® [UdE—k"H¬UYнëõÖ²c±¤jh:»Ì^íäõÕÃ7ƒJ܀Œñ_4c il˜Ž]O‹[czc×טµÓùnxBsƒµ a*‹ñ&WeÊíQ +«MœzˆŽðð,…'ºÝp‘ 3 ãpMg·××v›AöÈW½Y0Rè–œrÑùÚl¹>Ä17k.io¸’#I3àŽ¯€L—ãÃޅ© ¦Ä‹Lé,j¾˜IÅ vc[ÉYbdÎRSÙm®IKJYë»M¦Ö8¢á¥‡<"y~ÔKƒ£MÔ̓ȟš…÷S ì#a°`ŸJÃB¡g%ÜP)Ѱ‡L!®˜ˆ¤–XšotOa{úü?óå"_NW0«®óúgt¶|D¤w$6"Úð4é|C‘‘K& ®„Ðn·ùhý6þ Fî™õß×Ö5ù¯/GÓ·÷tø½§c÷dtX§zŠÉÛ6‡OŒo(®;zjË-]¸éd‹û‰ó*i.Ö(Dë3®l¦H2Êæ[Xn;Q¯e9«‡óB#9ŸYaôp0-ʜêõÙ¡Pxܳ٤­vBô±ç7¼×{æ'úg4ø=ø )σendstream +endobj +259 0 obj +721 +endobj +260 0 obj<>>>>>endobj +261 0 obj<>stream +xÚÝU]oÚ0}çW\ñR–´,ýx몵Bj[3i“òb’ ñšØ©í”õßïÚ ÐÂVuš4Mˆ¾çÜssrßcpD/£Ø½³ª÷.é^žC² “ø„…$ù`¾ \|žÝWhƒ™Ò¢6ð ï4v˜|£¼10ÖæQŽ]^R ,TYª•KXjÕÔÔ¸µZÌ‹¸F0M]—sàj®­ ±”úˆg®ã“>W®2°3˜Ö¨¹JÂù¦…‹%z›àÜ6š—pÍå²áK.s¸(¸æõ€[Ü+ïhô·˜ƒŒ‚ Ú¾Ï|z ÛÒAٕî?cj G“ÑOb*$Ì<ÒQÈÂqȺžlԎ¼Ád6ƒ•cé{ÝbÅ¥URYS¡´áÔ~)*AÈҁ›Ø’ø¤vvsþ%¦ÃŸñÊhðÒÂt–L¦ί¯¿®Õ0Ô_˜-𕝎—lª9'”õZëåÔHS˜ïaëB!ÊA´øÝ¼èxîð2Þߢtà­ B!–êtøâÖ½ž–U¤DIZÀªY±åó**¥Êü¾ý'tìcž +]#@Rù/2ák°àÚûîë»ùÏY7wÿ +5‡åE~sa[nñf±cîÜÑl³{SЭgblÍÈ ‚‘…Mp‡+¥ót¿iœ Ûgn’Wî@æ‡J?ùÛwHÆ·*”ÁF¼lü2;9[¼„ §/}“Ö;Hªr3z¾ýo|€Aý@ٔV+™{ã ¹Ót‹°à9ÌåöQ´¶ Š—#yÀËò lõ?éôg£8Œ!f§ôIåüÆLªºDçÌ­°”IîÒvQ\p¹`ùçs³>zå3ö}ÒûØû™k¢endstream +endobj +262 0 obj +663 +endobj +263 0 obj<>>>>>endobj +264 0 obj<>stream +xÚ͕MsÚ0†ïüŠNp°ƒlÒÜÒL“a& 48‡ÎpÖÊØ²#Éùø÷]ɆB ig¸t8„XÚÝwß}ÖÈì‹OU<4n¼MuUåoԑz'íÓÿI?;þ©Ýv®A­e—Р?óþ±~2ò›8¾{œ¥ýïÎãÃØ#퉨0s؈=¶O\´î‚+Eêèí\ò:·N¥âÎ{,Íû­Ú³ëá!MóžXȼk¹Z£ž÷?¥¯ís2MǓûËÛ۟ØÜ¢4j9¢Ài Æ¹iږ‰Ç¥kk)sºN#ãðT.B ¼¦E/^Ô/à³tU©hö”§6ô̖­™ïM~Uî6ë²Î,pSõ`¦­iôR×öo¶·6°xH›;µûëUŽŽšfE1ÂËO•"ºŒ¢Á¿þx&£$<ÅîÁ÷´ó£ó †bšendstream +endobj +265 0 obj +713 +endobj +266 0 obj<>>>>>endobj +267 0 obj<>stream +xÚµVMo1½ó+Fœà°–P’ô–¶i…” +¤j%.ÞÝíÚÛ۔þúÎØKHh•¨Q"!{ޛ7›V=úKàxÈÿYÙz7o}B’À|ÉGÃÓA| +ó¼³è¼¿šÌ ‰*‡µ\­Ñ,ºÝù5=4zõ‡ñ€ïÏ×Y!Q9Oæ£ñ—óËË`몢C R¡¨Ä +A‰Á­…i¡2R9Ì!Å¥6KYÐ}©èɵNc À JPÉqÜg(ƒÍOzáô•VØæ@µ¥3§ÁV˜Éå&(½ƒl׺.k 7Á·y´sü)3Œj#Û°èÐÇ¢ûvïÎ?s 1àj:ʉˆ`CJÃlWUqF ˟‹NÒ?Yt_?™|Ú<<œGÒF"˰rR­"Òß2›Të…z6·¦ª4A8gdZ;¤Úæ2Œ·k$~ˆ§ÒÎsm˜€N¯1s{¥oÊ(‚Â[î{8µÔœ€Ã_î¥rú$ž$ÿ-#™’εKwÕê ©BgþÞëÀqkQÀ ôò!݃ÜJšÀ;Õ^Òû#µ‘ç’I¿'ä;ÈÍ:áüp¸M…}@U—ÿ¹˜R/Qeµ1Á#nۑcUlü÷m™D—eÛ:]U˜·=I4>/Â¥íf0Ó+%?±xvòŒJ´–Ö}“|>ÿþJMbPXj‘í²Øfßðٟ@f÷ˆ»Á›­_´…ßc‘( +}Ë*P‡[t¤ãÎZ V2|l%ãéA—y(G%ã0ˆ9ŒOâºm–²°M˜‡¾˜·¾¶þtØÅendstream +endobj +268 0 obj +793 +endobj +269 0 obj<>>>>>endobj +270 0 obj<>stream +xÚÕUMOÜ0½ï¯å‡˜8²ÀB©V*mʆ7™ìºJì`;þ}ÇÉnXè.ª„*µÊ!ž7ï½Ø÷]f1LS(šÉ‡|rt•çW´’ž$ìòò ³XB¥ ¸Bk¤rhäô´m*Ñ`Â9#¿wAÿDcd‰„z‚JÖH‰Â´>H+ªæt_ U ºê Þwhèèêx2À §S–úð„³ã>8Ü.ó¦­Ñ«>à'È>-䳘âÂYýá“ÌüéÙGócÿác>ù6ùzHVendstream +endobj +271 0 obj +617 +endobj +272 0 obj<>>>>>endobj +273 0 obj<>stream +xÚÝU[OÛ0~ï¯8â©}H§Y +¼14—ndÒ&åÅMNÄ ¶ôßï87 Œiš¦Vªûœïr>;·#}ÌBûMŠÑÇh4= €1ˆVöQ¸¸û¥ã(CØãÆ(±¬ j'ɸÒhö€Ëôقä¦V>>>>>endobj +276 0 obj<>stream +xÚÍUMOÛ@½çWŒr¤Ú±+N¹QTP$ )1‡J¹l¼ëÄÔ_ì® ü{f֎“¸iZ‰KÅ؝7oÞó¾ô\pðDžÀƒá¢¬÷-ì n|p]c:}{ !?ïKñR ¥·˜Ö2YVZ¨>,Î]%ô4†_â}SH¾¸€Ë‹ð¹ç€ålŸ2õ€(MD®a: 'Ӈ«»»Ÿ ª²ÄC °1´e!g]ä|PȽã•,ª²¹Lrج %š^îÐö¨×+K$hl¹Å+!¡püà·a›ûR‘%š0¨íôÅ(!_1ÓÊ"çxebÙiºC¸f–BäÛé8l½Æ .òŒ¥é™M7_Áõ‰f y¶†C{DÅ|;Àª×O³¹u+´u2¥p¢Gƒ¢žw· Ëq‘¦Å&ÉW5Uê€U@ÒP9§IJ& é4è›u7ykà^´’é¤Èáª-O±4È6x®™®Ü ¥ØJ…Ò¸b&yC±2'”“Õ9v'ç/%KáŽå« +ïI!p½f’E´æ¹ÐǺôw X£Úú&sÿ"¯K[iSºÀ›.T„ÿâBQxJDfö¡íÚ¾íuÔА:™Íà¾à"5½æ"c¹N"¬TDU†Â3ÃYû„Õìz—0“F®`ÖÓå3ö;A´¡²¶PëÑøØ%¢JJÒ|ã’Ý%X´†²iQÝ8ƒVœ¾Sè[`ÔrŹÕÀÛJá¤2;IE«ŸÅ¹óæ;οŒ“É ›C@€0³‚'qÒ #Þ¥I坰¼³ câw¤#ëÎÙ·ÛØv»ðk?íµíGà˜ß~ëö)³ýŸÖp?a=¨ýfÏV%zqð×ââÄ+sÿ4kòßQOO£t£†RD¤#~Dò§½øWö3‘-kŒí³ˆóî°nƍ’ÜáÈ®_V“Ir€IV¦‚†¯7™È’åF[çüãóàdSítð=ìýè}c‡ endstream +endobj +277 0 obj +741 +endobj +278 0 obj<>>>>>endobj +279 0 obj<>stream +xÚµUKo1¾ó+Fœ’ÃÐÜh”THI¡@¤VâbÖ8Úµ7¶·iúë;ã]%l_j.ñŽç{ÌύÚôC·Ï¿$k¼_4.nzǰXóQØk a!Ï[„$U¨=L¦‹ñäãèöö ¸"ÏéЁ§ÏÍ ³Ú¨°Ê5Á¡—c¢ÖÏJoB@n•öh-wÿPRáºóÅC£ QÜmuÎo…a鎰Ì:Ü¡­*²Óoõ8²Y%Š”‹D’`î .z0+â°<[“¢ÐËóË£k¿Õ£T—AxoÕªðJK•F€§-' Ƃ6þP˜Õ&þH‘Ûš"•PROÀëÕèµa¿ùåYÜ,ÏÿMÄIò‡lÉftn48ŠÕ›ZR©IBÜÛÀy ‘ÂkWüŠC-·ÌXÜ»F-ø_IÝÏÆ@.R1)âw¾ZnÎ Á´ç;€ºÈþs1•&^"½H +k9C@¬±nב>—ƒ«dJôx*›Î›>>>>>endobj +282 0 obj<>stream +xÚåUMsÚ0½ûWìp +9–ñð‘[J›Ò’`n\{Mœ±%G’ÛäßweB€vÒáҙyŸÞî{õ“Ç! ‡Qƒ!$¥÷!ö.o"àâÌ Ǒ?†8½ø&l­E_…ÜÔbƒ d +Ó¡EbQÃíU?~ô`áЏ"~@è ku~_[4,¡bƒ¶× ÷ÈöjVtWSÅî!)š„~b +¹ƒ‰Í•„ÏýÈ;N>ðCÇ©2°D;[,`®R,®%–BÚ<¡›TR—(­ï`—7à#7'£AY´ƒFþ¦«Å’}Ä-²i!Œïjáˆ[äV¡ƒqqj‹ƒõEðÁhݍ¥úáf“€Ï¹±¹Ü@¥sé„LX¦UÙLb^ŒÅòµß¨c üa×­ÏOðÞáSÆþ±ÛL…úéÈ7ZÕ5›½Q^}]UENʓ •Ð:Kx‚ÏîfàW¯ÂõŽÂÕ:é·ÅÿfÆøÛkµ×9Ìj÷( ôµîŸš'!Á¥…ùj·ú¿€€Õ݌üÒm&*Lò̹ò&4!iB½“ð¤k¦RÒàÙ9Aù®Œ´lg…diÉJs4†|<% ±äˆÐ)ýÏZ>wâ0e‹9tæ?ZmÅÞ­÷ FFìendstream +endobj +283 0 obj +578 +endobj +284 0 obj<>>>>>endobj +285 0 obj<>stream +xÚíUÁnÚ@½ó#NpðÆk[rK£¦¢*-sã²YÄȬÝµÚþ}gmãB«DHQ•‘ ì¼y;ï=í>ö8øôpc÷‘ûއ¤wu7A²¡•xÌYI:ˆ÷‡ÛÕ|éÝH‰¥õ>÷øX¡±ÃdG¸8op^³Èá’„M‘çŏLma«‹ª4Pl@X«³ûÊ¢¡LU–y†)¥Ð֕X‚þïÚÑ|r_÷µ°Y¡à¦cpµ4]WüUØJ‹¾µ­ÄA¨n„Ò¢†%>kï¦èÿÙ²'©Ø í×ÈãÕ´öò¶uÿÉ R4’~Ò ™ƒ²ÞiÈ8#}[N6Š· +Lçs˜)æ5×÷BÙLR§BV{T–lµ_êLÑ^¥³>¬ôZÏÍ#Ioea¶Z&ü¿@Àj1%»tÍlJ”ÙƙҶZ8|•¹0†5¶ââ9‘ÐÅ]`‚sš²P/N ª—¤¥!»(.KK¦˜¡1äè9)%o„NA·|î‡Ù7˜SÞgƒ X‡`ԅ òÙ¸ A{f,pGd+èÿÌÀ3XÑyµø?#ߟ¬‡4‚5n›]ì3ã‰:”oG¸#À°¹ÁCÆO&~uâý'yçḭ̀oq@žáû@¾þ€¼º·þð0&WãQÔÄØ‰ Ó}™£kبGìÄì`Tíß~-§?aîr}ÙÕù1é}ïýDÉ]íendstream +endobj +286 0 obj +552 +endobj +287 0 obj<>>>>>endobj +288 0 obj<>stream +xÚÍUÍoÚ0¿óW<凄8DÀzcÝ:1• •6‰‹qà*8©í¨Ýßç$@Ki5‰ËĈß×ïã9-!} "èõAìZ_“V÷&Æ Y»Gýa !IÛÉAd•…Éý"SEö8ÜÏǰÎ5X +0 +¹–˜B¡¥²¨ö?Eƍ :ÉC˧Â~ÔbWø‡ÎË¢+˜5qÓÕ + #kµ\•Kyá5}c¹E‡Æð z°l[|¶Ëödô{ÙYv®\^xL{…`:KÆÓ»Ñí퟇DCóK|ߤJ¥àVª atuKžFnru€+J­]¹fž¦ë‘ëWMWáíÞ|;F+ä½^ÐwqÀ…^ßÏþhÿg¾20GSäÊ`ºãÉ:ϲüɍ·qÈ×Çé ˆ&5P¥À \[wìFþ°Ù)[µ,ì +¦jâ`¬È‚ –&µçˆ'2TÊuJÖýÜ—Ó¨œäÜÑ¡&Æo¹Ú”t”×[®¹pY =×Å;2à +6h½*óõªKûYSÚ{ہ ¿db©ˆCQaï,ˆƒèDâ†Ôñl“<ŬêµÀWV +ª”‹rG9š`p0AÖ{E&h,@˜üo¸æef¤êwiùA«e;|ŽÃp´ìkª1Ó&j¿”ü]Ç;Kó,kÄÀÓŸÔÊK-ð·â;tŽòºM-ãmÏaýO\¾ñ|°÷“Ïñ±¤q.¶|½Íçm¦ßE®ÿ?=Ê.ðhxæ’-µtW+}}z¥^üRèÞ ÙY¯Ofé³aÝÄiã]‘¡›³…@ ê]ÂEûƒ(ü×;5¸wZUl}OZ¿Z/ô66óendstream +endobj +289 0 obj +654 +endobj +290 0 obj<>>>>>endobj +291 0 obj<>stream +xÚÍUMoÚ@½ó+F\¤Úñڈ¤¹%i!%Wj%.{ÀÛÚkgwšßÙµÁhÔ(— +àùzïÍÛõcA@ÑÈ~“¢w÷N¾|6„xA‘ÑóCˆÓã¡ÏBúuõm:ófh¼O¸àunàuUJƒø'±¦Ð GþÐÆ¢Ìór%ä–ª¬+ å¸1J<Ô5p… Q¦À5T\6Tö×açvÚ֌kÛØ9L*T܈RÂŦ½Í%n›ä™á¦Öp‹Zóå^+ W.S®RPí<ûÄÖM¿SsGAÅs¸árYS¨®2®xbP184¥ß)à%”¬Ñô]åv@6­½¼mÝ¡›†uB1!IÃÄq|æý°É¢fƒ­¨ãénËs7k†—F$Ô©Lê¥ñ›M’Ní&=+Ý0ðÏZDÍV®ÝVžDB06¢¿ê½²r³«ùqð{—ó)N|%QËóµ t]U¥2D1u•^­Ä‘&O©&Œê‰DžÛ;”™ÏËL,3TóAÇ­µ·Eþh͌’÷@ÞãcÚ¼ÛÝÄ!xØáæ½Ëàÿ§Ù;층ߚ ɹÖ}Z»y®Á/|^•*QKHzi`2Ç“»‹››ë}æÖTàú­Û€) }Nøa•‰$k“š]6ÅtY. +a,$! .'ÙùíÅ÷ùàͰL&t'-¸ÎÖ`V1YԜô[£27¯CS­0õº}Y¤Œ¶lß +Íž:oŠ…ËÜÚ!Ìx +ˆ²;¬+a2¢èpY’Gt+µwÈY{°hD7È(t÷£=Î0.ª­u›sJuäq[ä±Ór½Ó0°É¡» £`Á¿¾`?ǽ¯½?~aqïendstream +endobj +292 0 obj +722 +endobj +293 0 obj<>>>>>endobj +294 0 obj<>stream +xÚÍUMoÚ@½ó+F¹¤Úa”[š´Rh R+qYìo²þÈî:$ÿ¾³kƒ ùPÛ\*_lï̼73ofï[ ºô0ÐëC”¶¾Ì['ß> a¾¢“þùÌãvè³½ý˜Î¼ 4Þ9>ˆ5Ü .òLcg~KŽ!0V9zAß­ãþÏ5*.á’gë’΁Üá,áŠGÌм†rÔTÀ‹ÈX£9ržûYړuè£guÓ£ŽècÕ0r¹÷|æ‡~Pcº¾f]Ôñt +WyŒÒaÍ0å™EÊ£2Å̸ä¼ý‚UÕ FPµ&Ë[z§Â®†èÚ¨ð¾Dmˆß>o&*BAT*E˜ðÀ%™‘N JË"ù•¨H+*G*ìúÃZa#éô\7ÍW‹Ï}ò`íîcØíž-:DšŠžO)·R”yD_OÀ¸|)ÈVBkr¶&ú‰òL)ŽE8¨=ó™Ë:ëÕ¢ÓdVϙ×ëùým^düœåMUÅÏXYRàÛs¶ö¡û?'‚}`"ö¨I‘ +b¶h‹ÌàšòY´Ùèêô碳輖WDE'‘O¦óñäúôòò×¶šð…nÙöÐòÊÊtIÁ‰¥ë‹I¸qm¬ä‰ñ ^E{)¿CKÍà£!ZÁàHq(”MM•¢\QÏJE&§zJ;ú›DА:VïÚM¿×ôȒcÔÙÉ +îði“«˜&î¯ Ö륩\ÆÓj³œÐi~»Y¨I›$¯®ª=Ô»ÇV|ËW°æôâØû0®”RSÊ©I‡­ûTíTä]ݱӣX9ËІaÂcX"fÍtn„I(EÇË&yL›ç¸ÞÃzøY¯Oû¢?¬·¡`§…D+Øj:ɓ”í¶9dí ‚îŸ^åá ¤ÈÎ<èÙ_ç­ï­ß‘Ô•Íendstream +endobj +295 0 obj +787 +endobj +296 0 obj<>>>>>endobj +297 0 obj<>stream +xڍR]s›0|çWìø©}@A˜Ôo­§Íd&NM€"Î6DéßÏI0®Û¦™~ßíîíÞ='?Ë2üt—|©’³oŸ T;®”—Rä¨ê…¿­l¶éùtÝ*çÈá;¹¡7Ž>VO , åLóRX»¾mûŸÙcoûqpèwPÞÛæqôÌ¡,Á‘©¡e}({†ýSlÔN4®+ä +÷Yå›Þàó‘>ô²·cóÖ+?:ܒsjÿU×yejekØY/ü0݄`î¸hU‹eö#×Áp¬Ê*íÉbKþ-•ůRÍ͎ü""O f¢Nۙzñ[n59͟T£1œ¡ŽÞ—B +^Ö¬)—ÓçP¯7Üö5µQkK2¾ÑÌÔë±#㣹ô4°)Ý|…mL0ׁûÇ'Ö{'è%ÅmZzÉyót|Öç‰ =ZËÒxQ-·ñ¹XÒ ³ ‚b:±ËùÄä²%òrvn×ÝÐR01Ý ³ÛèG^äܝ^äYh΋8k–‰sdÿ{Ý_«ä!y´‰þKendstream +endobj +298 0 obj +419 +endobj +299 0 obj<>>>>>endobj +300 0 obj<>stream +xÚ¥V]oâ8}ﯸʾP- %e Siµš~íVڝa*Í/&¾‰q(ÿ~¯'@`gº]!¡$¾¾÷žããc?ëÃýú0ŠárIvv3=ë=¼‡ø¦ Ž0åwðÁ-æ¥Áâ|úBÐïW!a<Œ\ÐíÓx¹VkÁ±€ŒÉ-à‹AY%5óÁ((Êܹ’¯æ#÷ 0 Ñ”Z"‡ùÌÁÂÿ@Vá¨53<õ†²Ìì;åISP 7‡­™HÙ<Ř%ÁÞØ"ž—A¢Ù(½²•¨”˜\2ãzñ|îš)P¯QïxH——ÑÐ@TÙCGÌ:f›c +ÜR>;ÿW>¦K<œÚ0EމX»ÊTVî$ “0GPk*MÕFÈçëªbâ+ÆWDFStGpØR'°J \+'œè0É©'3p¡11UŽœiZ¤Õєêyè֋¸,Î …Ë]HJ­Qšt eAœ/(þ–Þµ’"!‰>Þß߇ýøjеˆmÅÉ®éãirÓ(Õæ+Z-‡Ñ'»®Zªº^3z& 4kóþG&¼¼ª¤µÖ%%ñC"îÉC$DÐւÁ‡<Ÿ¨d…DǟÓé˜Péï¯ñ]×Ò7ùû¦wûø09߈·¥Íìç@q-1!ʊ“¼dÖéÇ£Ùùë¤éæR&ƒeIîjdÜGFC«ñL󊄂í£iÒt£ç‚ûñƵ>ÆÄnkÇþÒ~¼Û.ë¾2¶ÂtfŠS®7 £ z/ÃiŒ~ˑKCߒʉ7.w…¢cŽ’“9:Rh§%¶æ¶¼õíîØÂºtÍ÷ìWgàb¯{93˞Q=û&Y†Á›Ýô5534Ků{·«Ø…ÍéH«é±¥yG6Ô^Xùe1@TTzs‘ÑÅ"£''½ÿã±?ÇrÜ_5ûÛïsVòßÜRÿJý ³õ/ :ÿªÇ ’T5êUqxb’‚öí'À5ÊÀYo 8÷ilÞ% P Z®Yç맏½¯Ÿ`I¾R,ي;;¯òÙËHЪ7ëÜN'½/ÓÉá„ȇíï²§/w¥£{’ãÓ»€c4c/"+3°tAuªµî7G›©¹^Øùs,Œ=­TǁͮUº»od½Aè»ï=\Õ±GR\Lë¢8 h½/ìPüÎ~¸Ÿž}>û Óendstream +endobj +301 0 obj +1084 +endobj +302 0 obj<>>>>>endobj +303 0 obj<>stream +xÚ͖KoÛF€ïúž¤Â¤HêåºÐ8m- ¶Ê¡°|X’C“ñj—Ý]ZÑ¿ï̒z”qÚô؀í<¿yù¯Q1ý$0[òo¾ÝnFӟrHؔ^G),¯çÑ5lŠñ6]®`²ù@ó^`(t{mžaS!ø\綦†}-%dºG/¥6;V^‘±0™‘a2ìÐUº¸™Nï[‹F‰Þ4ÂZ2Y|ÿPiëø«û›F÷0½7hukr|®`_¡Aèôa'ì*¨œkè-¨úÃÞâ _²)øÍî2ú£ }Òùºjå#Ì[cP9¨wÄ}®Ö*êͤËhÎf8Ë÷¿ßA×…dxó~ýGø]øƒOßv¹k%k²Ó;èƒå”‡”zß©ÁA¬V +[‘í¡`;‰àŽÂ³Ð6àt³¬9dÑ4²Î}¼ü"ŠÂ¿Ò×F7¦a‚Phz1µâòtúV±…Z=‚…{ Ê¡ù a݉‡¯3uÖ:ʃýž õï*Á/8–žÅ›.#´d·i°øÎ'yùBl¬cöÖiC±_²ÞQ&YrôŒ¼%$ÕÇ Ñ7h؞L!l¥%]åzÀQ7ßB²âinÂy܍Ȃlü¬3Ø õS?38iÍY‹.â#éD dB)b†ðvÌ0¶ã$]m'ÛI§¸ì'î‚ÿvÌH!!m㪩°Gùù§ò\¯ 7âØ󺬹N½”µD"&|»uõ'’°y0ülyn|ÐYäGŸ†“éð,dËc?œ?¥PÔVd¬Ý{òƩע~”¢•®·áËé ÙOÐ9üð(yJ#ú„ðl-„Ó£®u¸¯—q†Ô}ø5@ö þ/ædRäOÔÌ8ÓZ¢PÿÅë¤ñ.ZG¼°àÝ:|ûË4/Ø¡±•n%##,ª@NÇÔ Í5åâí҇§#Šëèñ•3-n'| ZË ÏïT-µév–­DÁŽúhNˆ|é.í”BZäý߁/ûïçj5§ÐòàÖx¤¾Ç7iŸös@Ϻ/å4­AÁ÷ù,Úßéc#êÖ5­ã„i#æÄ5‚×ñ$އwĂâe,ù>3# +—Ìíé,­û΀g»ð/•åùá3ýIކÇçö øûGA÷WñÍA¨+øU<ò¿‚?‘oí•÷zë›Â[¶5/[•û ”ÛñGêˆW—¹NiR<ð | ú"^÷eHV)•p™öR~sÜý㟠¦v·^³ZØI‡«4fátÉ_Îi´€ø Nɏ›Ño£¿hùendstream +endobj +304 0 obj +987 +endobj +305 0 obj<>>>>>endobj +306 0 obj<>stream +xÚ¥VMoÚ@½ó+F9Ž×|9‘rHª6Ôª´¥R\{ Û®×Îz„ßÙ5pÓ41;3ï½y;Îc‹O/ãú#ˆÒÖÝ´uùá +ئ EF!ó˜Æí¡xCˆ2Y¦ª€Y[(ƒ Ô³6»Ì:³Ngú‹ÀX•Ø FÞÀ&N—øšÆÑb^„"ÇH$ 0We:G YòzÒd°@…šÓÙç%*È5uj_ $BbၭcÂKià‰Ë- +êÍúhQó*d[J½~ßm(ç\³Ê1$ MTèø4–\óÈ . §o„Š–'h|Qrå +8„Ùï º52\ÅÀÆÀ5(µFe(«(ó<Óãb€¥ïŸæ?& &—™! æY&‘«6ç‰@‰†¶Ó+".>Nz÷Ÿ.pŽ­Q Ȕc\ DÒ)†cÁ ĺüÑ%Î:éš +e.1_® +A=֍6bÒºŠo:îÔL¸,¨è©\ô´Z!,xšò}û3Ÿ~¯@•xÌ9dz¡¸ŠìU¡ÑFF>I¦]0+M^n×XÉ_¶çN •ÕTÚVéÒP¬ +kkQn`s­™†ô÷YH¹½iR,–dZ¹þmÍìšwA£mgÄÊ՞€µÎ;Îó+ïíqïD  Ïsi‡Ef° ¿a܅{Hpmï;[cxÖ&¶úXQš¯ª±WèÈ'eá.•õg©ñ®‹dÖ~¡ƒ7ð²™ShÇÔ)Î*x4M}éFUç`ì1ªV¼¨Ù¤½þ¾U®`Yâ®Qz,ô¯éÝè›wÈ'Ü.Gboã:3Üyd©ˆ”/ðèr´Â7¬æƒü·}(ÏڇR(|Ó*9?„vëÕ-~ö5pf“l½yfL–îŽÌ¿þ|û³q^»ÉǔX‡S®´Ÿè7Ϩ‹57=xןñ±¤ DÏb+ÑÁ-õ÷Ó͸#O"ÚYˆU“ÎA[bbÞÈØ¥Ýg6øŸl¡âW#}’m¸ÆËÆöÉ>êûæw?&ßá!Í%¦ä˜êâ)&›Ö«N÷Ɓî?:ƒñ€žîx0¶_¼Ÿ¶¾¶þ‹Ußfendstream +endobj +307 0 obj +812 +endobj +308 0 obj<>>>>>endobj +309 0 obj<>stream +xÚÍVÁŽÛ6½û+ +ØÀZ+É»¶S ‡´hÚ-°E] _¸ÖÈbK‰ +IÙÙ¿ï#i%ZwµNs*,@²93|ïÍ<Ê&¥ød´\ùk_O¾ßNnß½¡ì޶%VV›,Éi[Ìî“<ɖԊ/Œ°ÙÍÒo}ûçn¾›Ï·!ý޲,¦/òUrçÓ·s…sF>vŽÉ¶¼—¥dK!qµæ ÂÕjìa±Õ:ïŸùC'”dÙì«ÝÃ9G!•x„·^—fƒ†°ƒÏƒ#w³G­‹æš2ƒœ—íÎlÈñÇsoÉVºS=rœ€ž—À‚ð,+ÆÍx{÷ö¿Ð£ÂA©üaé‡g7@øÎ™Žws/¯©;€* +饀1¢,/d•ð:.¬^ï Yá:Ef¨Ï¼óv‡™„QÀãBÄÆ‹¡nüyŒY +d­¾Oƒò€ •òmª„*Ïîäa#š²C:æ8<²zÑÛ¿®^ž’ÅÁû2p¦7øuíΙcÂõë 6)ŽÜ¼…PVø† ¬¹Âë9D /ôî"\Èÿ<ã¥t>õ__7~:¡aÝá=ˆ{«­•°' b3(TàLk,zh“‹½_”¹kzHEÿºNúÈÆÈâ¬Óó#‡Êój·ï6gý³uŽÖ­–i¬ýÿÓûºU ´îÓ̽xði‹½X£ÇÎ7þÇe¶J֔þ·V?n'¿MþÓÁendstream +endobj +310 0 obj +849 +endobj +311 0 obj<>>>>>endobj +312 0 obj<>stream +xÚ­–]oÚ0†ïùG\ÁER´»ØG'UZ+¦²]寐âÖ±™í”íßï8NhÐ4UªÀ9_ïã׿zŒè/‚Y ã)¬ÊÞ§Eïêë D ,rz2½ŽÂÙ`ÆaÁV³ ¤ƒ¥R™L‡ÃÅÅ'E>>ˆ§aââú`f­æËÊ"˜ ®xÎÑÀ¶@[ ¡ä—´d +U‰ –>kƒuqŸ>X]a:¥A*Û.æL·J…¤Gc?èFsi9ÕµøÛBΚÜ4æ¬^˜¨¸W9ôH𬐌Âk/x óùøØÎov¡ ›`2òZ)4Œ`³ÉÉl¥™“늭‘æm–¾5+g-r !ñƒ]ʕʜf•×ÜÜN9µw_ÛÞ?Q®ö½V粓C¸Ë»[%Ÿ¥ÚJ·#•$¨´}™ ’ÐGÙ§–·r-¸)h{(šS•˜…ðÆãpÚ‹kÝ%{®'¦}KQ\’˜ãæÜ“Ø*‡K\é÷~×ä2þ‡=ï]vݔ,ýX(m§ #k·CuUc‘qtҜäÒ_%¦ƒx2¹ˆ´ìÊïòmµx ^ŸAýB´5 +fù ÉTžN %ãWVé?þ̕Þ2í0‚™‚½òg¶–IU(Ÿ79uW…Æ8uc&0oN×E·fB·æ’I‰:@rV{A·À:֜KŸÌ!¢*Î_Ó;å à#íÞCÝ>÷)ƒ”¿?€åN%¿aœÕ<©¥§\¿bö÷¥’Øïô`– ÛÖ}úê¤ÁªÙH1–iûÙ]7ñÑ,¦†Sú_çÔwåF`‰Ò’×Èt¦ïæs—øè`Îü^Hf ¦ŽŠoÜÂí¢÷½÷œM¦Šendstream +endobj +313 0 obj +757 +endobj +314 0 obj<>>>>>endobj +315 0 obj<>stream +xÚ­—Qs›8…ßý+4}J ’1Þ·6Ýv2³3ëmÜ7¿È Ûjb‘H6ûë÷ +ÙØÔ&ÀÌ&glŽu?ŽtÄÕß3‚0üÅî/ÍgŸÖ³‡/ ‚Ö;¸',LÐ:»[Úò¢U`,¯l‰¯•EÜÚJnk+)E*wRdA|ºî¿„vR d5*+YÀ‡b§+¸R̓d8ú¡·!r…^¸ªÅýúÇ £€D!u +]ˆ"Ü¢BŸ +˜ƒ®U#û" Ý_–ˆ0/A…±j²0jï¦.K]mîˆVïPÁsoèbs¿¹÷£Ä­#CæFÙÜ=~_=#ċ äþ ª“ž]ë/lkö¹Ç_¸T|«Ä¥¦q|{•`W¯ü͸”àÆ"pè¨ÿżÆýó˜)Ž¥ïûĎvV}+xäþQ$Š:¸×Î÷nÝçQ€¼,LyÉ·RIû†¶Òk¤1ã$„·©âÆÛÐ.°[‹E”꼬Å»J稠à +ÁâYÀØ9·RMeWeµúìWé/e}µVJ¿ÊbïÑxÕÈBd¿yæG–,ˆ€.¼Ÿ¤u—É‚¥Ø}òY˜´’¥+í®ü¾žáCۗo_KÂb1øŽBŒ(†û‚’Ï7ÄdNZ5Mb¨sVwÒìuðÚX„ÿÁþ‡4€8òxOpo­áÞíL6‡Gc6ê˜þjD:hô­¹¶Î{ceÑLàÙh¾FÝËG°ß [BÖ!|äÅqƒƒýl«xús»íu4\£îƒ‹–ØÇ¶…KúáR­t5%nю…óê^¸ö8Á܉Üj{@FÂ#؍›(ò½ -:ð*{…ì ‘ÇlBt¼º—|Ž»¡×ä°©”°qèÚ–3ÄÆØ„¼xu/[„/ÉØ5Y¦ÑÎ=R]Jÿ˜k!ebãÕ½˜xٍMò.è›[Êo΀u|”¼º˜&ËN”¾±Zë"=Œ›ršD‚äÕ½hñ²$z-Õ/îi9 +-Ž&$Å«{ÑØ²“vm+ái;ŽŒErâÕ½dtyÁ•Üà2Ўä¢Ñ„`xu/N.ƒËìšìý ì-¹È$GuézèïÏÁbÏÕÃG6‹é„Pxu,I’ËPÐAئñº`uèOϏé7Iè„Äxu/wœ\&† r+^í][ +Žæé„yu//Œx£äÞÚ@}lCðFþ+†Z6Âè„hyu/-=/`·~ñUË›x^*™J §†½)Ø 8£@#žmîG5™„Ò ¡ó꛽ðù”³˜{—Ý!gÞ9¬97?ožtþ§Sàu±óñN.0«™ËJzÐÚ´jÓà9þ*¡Cr‘+|6XT@á‹'ÇâdáÒ/>½ î̈ÈEaýSº¬§ÕÊ}-ðê`A›ù‹šé¤‹(>>>>>endobj +318 0 obj<>stream +xÚ½UËnÛ0¼ë+¹4JŔ%Ë=¦SÈÁå›/zÐ5 ITHºAþ¾»¢ägà$mQèB-wgwf$òÉã0ćCÀh yå}M¼›û8‡d;ãIèO )®ï–óû&,»+Sc„՝Z©jãC²Ik Õ +±–µ(@¢¶2OËò¬‹9–µšÙ—F@j­–ÙÖâª.¨*ݖ–2±büô†ÀøÈ¨9ÿd| +ÝÜºÉØhäi3òC\hñ´ÆÊúÛlQ§•`ˆ¤žq”Õ57ª5P_‚x5X âž+ Æ~HˆDç"Þ~ôR¢]–€èD‘’ ®RۊÑW­<s{@iÈILÿ„íT"F i:)Ýâ¿:*-Æz–8Q¶óâ3`je!SvÓ÷;¤k‘Ë´l‚«Û‡‡åbú¸¸A ìóËquŽbG›8¾ÍË&ŇÿWiñ–E$Ëe›Nüq¦ÁÇm:ÿ|þ·ONœ½Mq§j8tyäG0ïx·?:Üö³š3o£¡› ‹|•¨²Ž¨ù3ê÷ +µ„×c"Í7½…ýAÒʰK6ý¶Ãê³ 0¯y(ÈEBmar¥QÂFՅéÏ+CqQŠ +O²cl¶Õ‡¶_úð#ìxX´ÓßÞ§Éq¯7$Áä÷)½§Ç.gäĸN‘IGŒÇêFÜ©B· ̪Æ!µ×ÁÍæs*c.›ÅÁð¯ø0¦ ¬Åq +Lï»÷Z?¸endstream +endobj +319 0 obj +570 +endobj +320 0 obj<>>>>>endobj +321 0 obj<>stream +xÚ-1 „w~ÅÛªà¬Ñ¤Fܺ4öµ©)Ôÿ¾Í»å}w¹[ˆžN@¥²žŽœ,Ù] Ø„–L–lWœæµ{OèÐÇ6޳‡¹‡Ú˜Ò¾ýeé?\É %W,/$p`ûd¯¸lâèº\©oÒvšævÐ"`L•™¦Gê¦lÊÜs±äF¾ìõ.çendstream +endobj +322 0 obj +149 +endobj +323 0 obj<>>>/Annots 59 0 R>>endobj +324 0 obj<>stream +xÚ͛ÛrÜ6†ïõ¼Ü\ˆFã@‚—‰½Nio¬••ejW)2'¯ÝM4¨1“ª9ØU’à?~6þAè3hTø M¯Ó5·g¿\Ÿ}ø<4Z5×w ¸¡ézÛ\ÿ×õÍ·‡±y¾k>>?­Ç§õëO׿ŸýûúLµ*âˆ_®~¦3®õÍcã[M??4_#{Ö}õ¿æÃg×Äÿ-^օ®áƒæ]|F>6é[ÁÇ(Q¾Þ>¿Œ¤]€‡hOþ¼;î0¨ Ömîtë¨AÿðْŒá>vڄHÔ±]PR@õµ”HŠêâ{¸ë÷w÷·7ëûç§u}¸â„t­i§†ÖNÚ¥ 4*ªµ¨˜®)FPQÝ„qF}z¾ýñD{Ÿ'hmø^©¿ü9®þ¼ÿŠ@«Ã'=²ú°hΛðMžr5OyçÓÈôò„g”B2,Œ&ÆÕx7®Æ§Û1y“ÚþÄg½YNX× ÉåRVacÓdw½B»ÓÕÉÎD¯Ã·‚ˆa&}üíòë ÉW‡¤u*ÞÉÂ8³xL¶Ñuǽ-5Õ]—-Ù&\ð¼µ®Ùs¼jMÉ¡0‘¾¬ÿ?®ÄΗ±M4‚Fq‚±Ø<ôI̳laPšm"ý¼É&L4æ0S1 +‚95–4Œ¥0R{"2-ýq•¤…ý1¥Vjl´ +HSÒԍ‚x},?Â‰sqyù>G\úØ ±² +'ÎoW)aÓâãäîDMze„K§†ð e[’¼êÄA÷” +Ûí½™Pqõ`KʼnµxåÕqqëiÁâûò2®’É£ùôÁ—Žz/Ý¢ëØ¾O‹®h øó×±½Ç…—]v†u±æ4Œ¥T(Ý֓ö~9ómgÑkã@°±ÉtlçÐtmÕv˜8øÐµ R˜H—«û§õùž¿½Ïˆ˜¼z¤8§;C+k{ôó¾ö½ŽÚ;@cºØ`c çXï%ÅÅ¥¨-AßVpI¼¾Ÿ0î q­þǏñuiÆ´Ã1ä®)lúd|(Cj…GӋëšÆD"$ŠâÛ^e&z§…$rB^¯/ÁoFÊk8¸Ð¾â!ÚæÕ66rõ´Úá²ÖV«'s@¹8| ¢8¡>®Æ›õXY@°ò͐܁˜¥{˜c>_Il€T¬0÷RC$6hªx­®›‘pmP (N°­D˜Ù.ú³DrbJ±G؈ª¨l¥, +¬².‰ºjLÂñ(Šl{•'äÁ{ $w fáêà™=,»‡ Y2=ö`#»‡ñä¦âL Sz¾ŽÉ›Ï^¯W÷ß~¬Ç×%™A|Q!ë*+怋ïÓ +Å{QÆ>ãzÜB\A‹›;ýœÍúMû–pÐó2 JcƒE-5Dƒå¢Ö՗ D‚ôʧ@Q܊¢¶µÖ‚9. +6w°o·+÷þìVW)QՔ*«š®j]}Å@$­DQDUÛQ\bë4ñ 6w€ »”°×·w5‡/Nb`#;D07¶¯øS┊—Ïn^_—7$3ˆ· +,wð§°ÕÐ-§/ô&W8läô…Þr…ë«ÞÀ$¬:Šâ¶ÝUiâÅCæöíväA–5q;•ŸÕ°!Äí€K\_õ&р%Šâ0{VÛV\ãò¡sظ¹÷åCåÄØ>ïEbC˜ƒåÃ&A›Š=Lñˆâ¾-×¼IÙ](Þ0˜c¹ƒß¼yð×oPy{Ææ +‡ ‘Åf:‘âëA$ðq»°@QÜ͞ÛjZ PÈaˆ‹±ËÜÛ½Hw7pUqµ8|‚ !®ž¤­qhÀz~ø„P; +KP­ãÊ«€r‡Mo6÷ŸÁP9 +ªÏ»‘Øæ ¦'CÍ7écé‘ Š{QÓhIV“V°ðµñŒÌüÆÝÈ¿7†Ê·Áæ +7Ø¢À Ӊ“¡ê „abÊäeÒ.*âÓá›6‰ á‰Z>Nì=ykŠzq¤Ä—'Jüt d¨aP??N¤%¬6q‰+±QQ¯7ì;îw¡•c žÎpž¿§4µà>SÀÅKŒó­õöv|I/„—”̘xƒÜŒIáaÓF#ö8e-WÊP±8W/×±¸K³_\ŠZt‡Âݎgn“C Åð›É¿÷]ÜV«Úy2:lGmËÓ!v:jiö‹‹YQI¢°–»ÛkJXŽIX ë [°ß£’ºrhAãi‹4µ/w§! J\µ›ãü„Ib^¿·U13-ºdRx8þÖ"˛‡ ¦ß5öt.ýúäWâ}Vsñøò0N¿ª×ùâò2M2ÐÍy¯°ïIŸÿžý ­ž‹îendstream +endobj +325 0 obj +2319 +endobj +326 0 obj<>>>/Annots 106 0 R>>endobj +327 0 obj<>stream +xÚ͜[s·Çßõ)öÑ~ ëð[jיdÚ©j«3}Ð %­dƼ…\5Í·.ÀÁÒ¤NI%%Îþþýܔ_/hG쟴ã½ûëv}ñ—«‹wŸLÇHwußQiº^‰îêîÍÕâf5tÛûîÃv3›ñðöꗋ¿^]9±÷ƒºŸì›“®çr®»uG ›3(­º/?ybÿнû$:JÝ*ÛÛXû‰bNéœvO~FÛ2lޗ€÷á_—_fŸ‡_†ÛqöóöæP!#ÖºcL§/ÉäÏïÃat<ÎíG÷ç'ûƒ‘†ö̵.iïKÐp§/ã¶õeM}#,|e ‹À{±¾@f\ÌՄ @þ<vÛÍap@Açâ¤3úd»m[u‰±-XwR§´Ú¾@=%sâV¤EÏZe…rß“¤Î$/ë—aœ}±"+¹£S,Dò?vÃ~1.·¯+›óSÜçêìG±4½]q‡RÅÒ([¡Û.‘`&£‹Qœx/Ûàf2¦¬ª%Ù néúäÑRWsû3©ëKH]qÛ!Êdp©­ÿ“²Àuþ@'\“¨…7œÖz«;ƒìOþí…ì R‘”ÖxÃ"ˆJ6%YgH$/è^Ðÿ,o‡šá"ë¨~е™[úŸË3úBEã0ner[(¡q+UÊmü®aþ­-`1@¡Üö<©ˍ]gÂ%TÌmÙN,tS[Û×"këKH[!RjãÏp… _Ãb€@ î%Ú™qí· C o §nj7́Ÿ' î È8MÙL´Ì@Ô΄&$g‘”T½¼üX“Q,SË)Ódèk:CCä0‚©ÂY͗ЦрÅ3¼!¢¬$¼DÅýÆMˆ³… +ú̦ð,Y G‹¹PB²1϶!Œûg‹b’ß>¬‡CÝ2ËCŸŒ!ˆ¸`+ŒáÄÓñd»m¡Jy;Ó¶áß¡Íï>IX» ,M>-BX—éí»YÐB-P~Çýòæqü*^¨3¿Æ/PÖ­Uô"X+s_Ú’„qcÁš¬èep1Y{ûÄöIoõ*ˆP ¤±*]’Ÿ·ž“) ê6é7yý~©ˆï½AHê-͸½PÈÖ d¼&9zÔÍyåõuçŸÝ:G¨Íw%FZ™U‰Œžyýfü}7Ԍ Â~Ф…1Àã¾ ¿ÿ¶Ýß]¿…íŠS¯õš=ĕ·Å £/ â:X¢ë#Öê# ¹å-QP0è¥åæ~[_”ÐÌ4fÚ¼PÛMÃÇë7”©ë· nÎw¤)4~Ò´ð$4“aÂï„æ-¡ÄlB%% +êB¯߆Ùbs7[oï†ÕÓp̳ôÞ-N +º Èðï ®N2çk*K©OkáËûR–2ȍsWÑPHT¸%Y‚z€²ûemòœ!Ù»ÅGŒÀ¼~cqAHªmÅ«¸{+›r£s6 …¼Páö-Kg9ŠL9P ¤Ÿ·7O“ÐÃV`ê¦o +êu5¬w«ÅXIÈá|LO1À|7%³Óoî?Ýo}ýá~íïH(äw„kðÖLđCm‚“%ê=êf±Ù ûÙ°¹«9|FX»!ýÀn6‹õP؍<£àM}Íi4¾6DG…[i4’¨tÎ[  ` ña\ìk»¥ãT6Sh `1ëìN`΢sSe©s ¤²4ó4Ž[94’¨pÓîõ»Y-n¿íVÛêÉJf¸ù¤;*ˆ1ÀÄÌy³Ý®†Å&Mù¹}£)´9¥†Zô1¥²fJ$*Ü(*PP°›ýòá븪3wq󙚚”}L©ËÍ8< ûë7ä=#$ŽhEÎ!xSdÎ|¢ :øٟƒÈ²%2(?BA=Àn·«Çõ¦¦0/xþ, àÅ"…é{‘CÏϹkÀTChjPòó$4#Qæ¾%3p¨²™êêvW›¢gÝ[Á§M‚€€j/>À⬱O7lס‡Ø«ìê4;ŠH”E‰,³(ésU­®eÎ + +Ôì~96ÜÜ4^»9 æÅ€>&Щ»¿ÎT¾¥53,çÒPÈZ3Ãs.Õ ­#‰r7ú +Ôìa±^/jޓŸwî +Z à1"d×äL+ÿ¦ÈÊä< +HdMr5-‘D©Kw*ÔGØ×Çê +'?ífƒlÚ,ˆ0$ñŒjòÞþ4–gØM{|$”Ð½Ê¹”’ÖD‚Q·>/`1x«ºÓçÇÃ=9A€š?s£!œ×Ë£ÖA‘Û¿†5ûLâK&¡„úL¦Wƒ6ãª÷ž!.™m·xf7ÛqÜ®+H±ïˆpT"!àxŠù÷þ¦˜æ”ÔԖt&JH[Ar&¥Í3¹óûU "Ïë»îÇÖ®XD2æöhKdˆÈ×Ñ÷™*3|Ý$”ÊLåZ»ÕƒÛ纄Åày•ýj©¾}®“ñ£Æu”KK™õ©ñ™nˆLñ½“PB"S‘shív~<¬F'°†5ëÈ—ôܶyɄ]ßÒíÍY–üM¥¹@ 0”Ò\æȚ Ñãý€w¸]¬–›‡ú¾n2ê6RJ ÈïìëR´µ¢Îvñ¨)5£8²òreYèæú1¡˜JàRè@ûm¿¨Í1ÐÓn-ê=¹`1IG†ñ:{„¦~ÚOI¸~ãÏäC!ŸöS’.ñÆiä(?1À¨ÒååÇÊi~8dÔ +êõ§¼.×ÐÜkƒ® ™ò–I—„xó 0n²  +N¨Ònw7Ûx—^ÍV‹ÍãH×.Ò&ØÚoš‚ Õé~€ÿÜ4ùÿ¦Æ–ž]ÒåÝ ®ñæ±¼Î7ƒHÁ µ@rzºëV­…H¤Ù‰…*hn¢Ó… ï]i;ëÁMKÜ^çÌ^¹®Owxó40nýUrB-¢¸ÏºË–QnÏX—Á\¨6içõHh·^9‘Ð-Q%ºª#˛:2½ÿ­sw€„á&§×t$zû×ÍÑ*ã:a¹Ñ*‹ë9LÊt|¾ßÿhå1As´Èb"]Í­kߢ¥¿Ç7IaséÖþré;=î¦f +µì»)ìµ_8zº¢ÃôäT1æ/ÑÌ_,Þ¦ÑÖ=˜>:RœOî™Í7šQΜåc.T›ù“×ÍNø›åAÔÜf’þß~EaÖ»-¾Þ ßûî~ZïVÃz،aµ½ï~º¼t UîÔb¦Â±ÿr ¢üóâ>‚“endstream +endobj +328 0 obj +2756 +endobj +329 0 obj<>>>/Annots 116 0 R>>endobj +330 0 obj<>stream +xÚ½—Ks›0€ïþ::ˆž<Žm¦éäæ6îÍ\+ZƒÀÓé¿ï +V°¸1¤“¤ÉŒ=-Ÿäý¤•xZÆá_°X2±ïÅâãzq}›2ÉÙú “²(Öl½[®³í޲û9”-›újýcñi½à!‚ûîãëg@…œEʄ +XÁWר³{G?{ zd×·š áÆƒYDÊ=šP‡’]…€ &Rªñ0؏°mV–¶ +ê&«š`g²Ó¾¹Ì¦¸‚IÃ}Ò7Ë2+ìf)d¼¹Ú\9®Qa ‰…Îðíÿd:“|)èO~ÛÀ‰»KmL°šK0’DœöÜQ‚=Ì'øt<ªÆî&’KP\!]&).$µ¶ ,»‹Ú AÐDŸÏæféh•:ßé® ð@[žŠNŒŒßEÌ¿«2FéUuA•IÝ4Q•™QåI"QðkG(ìGUYýs*ÁË%ØíêÙ zÖE¸ò'ϧêHŒ%ïçkVüJÞKjDRÒï¦hNr¤æ°RG ìoQ•}:ÙºÉËÇàTƒ(WV‚l¿?üš*~ +CÄîˆ áô ‹!LI+pÌÃýlé3â_aL‰'Q:ܺqóá¤ç¬ IÂ1¬Ç¨®ßÞõ²³e>©…PÝ’À|Fc`€äbÉá}6<± ðÄ7W3)..0µG¦‘nÑ´ œÜ‰ý-a¢¦‘G –·Ò(»‘´êJÚe@…Âi¥8ìGÜÍ>«ë‰ªHžwG£9§ùÄ}hš*ߞÛ^lµ|mö_Uêæ¶•VÃÕ¡km¥µ¿:˜PÌm+$ Xšé…ý+l±ÅÝ4•t‚}ĕF¡>@‡/-p„DãŽØÑ ñ¹}$ÞÇä¬%ÅÉ­¡mKJø[ƒ™}Íñ$awîRö# -ª|J¡t¯NfÌôÂßæ$Q†Ó»Z9"ba~ñ¿6Yçj˜9ï_=|õ ”‚•)’¤«Ç7ßV÷ì®8îm/»Y“J÷ò{·Z9‚Ÿ(XËvöyžcj¾,þՐ=*endstream +endobj +331 0 obj +865 +endobj +332 0 obj<>>>>>endobj +333 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS047Ò3S072PIÑp VðÌ-ÈIÍMÍ+I,ÉÌÏSÈOSð Ð Éâ҅¨Õ…*Î, º†prÁîendstream +endobj +334 0 obj +94 +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<>endobj +356 0 obj<>endobj +357 0 obj<>endobj +358 0 obj<>endobj +359 0 obj<>endobj +360 0 obj<>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<>endobj +411 0 obj<>endobj +412 0 obj<>endobj +413 0 obj<>endobj +414 0 obj<>endobj +415 0 obj<>endobj +416 0 obj<>endobj +417 0 obj<>endobj +418 0 obj<>endobj +419 0 obj<>endobj +420 0 obj<>endobj +421 0 obj<>endobj +422 0 obj<>endobj +423 0 obj<>endobj +424 0 obj<>endobj +425 0 obj<>endobj +426 0 obj<>endobj +427 0 obj<>endobj +428 0 obj<>endobj +429 0 obj<>endobj +430 0 obj<>endobj +431 0 obj<>endobj +432 0 obj<>endobj +433 0 obj<>endobj +434 0 obj<>endobj +435 0 obj<>endobj +436 0 obj<>1<>2<>6<>]>>>>endobj +xref +0 437 +0000000000 65535 f +0000000015 00000 n +0000000219 00000 n +0000001785 00000 n +0000001863 00000 n +0000001940 00000 n +0000002019 00000 n +0000002095 00000 n +0000002176 00000 n +0000002234 00000 n +0000002338 00000 n +0000002443 00000 n +0000002548 00000 n +0000002653 00000 n +0000002758 00000 n +0000002809 00000 n +0000002913 00000 n +0000003018 00000 n +0000003123 00000 n +0000003227 00000 n +0000003332 00000 n +0000003437 00000 n +0000003541 00000 n +0000003646 00000 n +0000003751 00000 n +0000003855 00000 n +0000003960 00000 n +0000004065 00000 n +0000004170 00000 n +0000004275 00000 n +0000004380 00000 n +0000004485 00000 n +0000004590 00000 n +0000004695 00000 n +0000004800 00000 n +0000004905 00000 n +0000005010 00000 n +0000005115 00000 n +0000005220 00000 n +0000005325 00000 n +0000005430 00000 n +0000005535 00000 n +0000005640 00000 n +0000005745 00000 n +0000005850 00000 n +0000005955 00000 n +0000006060 00000 n +0000006165 00000 n +0000006270 00000 n +0000006375 00000 n +0000006480 00000 n +0000006585 00000 n +0000006690 00000 n +0000006795 00000 n +0000006900 00000 n +0000007005 00000 n +0000007110 00000 n +0000007214 00000 n +0000007317 00000 n +0000007420 00000 n +0000007745 00000 n +0000007850 00000 n +0000007955 00000 n +0000008059 00000 n +0000008164 00000 n +0000008269 00000 n +0000008373 00000 n +0000008478 00000 n +0000008583 00000 n +0000008687 00000 n +0000008792 00000 n +0000008897 00000 n +0000009000 00000 n +0000009104 00000 n +0000009209 00000 n +0000009314 00000 n +0000009419 00000 n +0000009524 00000 n +0000009628 00000 n +0000009733 00000 n +0000009838 00000 n +0000009943 00000 n +0000010048 00000 n +0000010153 00000 n +0000010258 00000 n +0000010363 00000 n +0000010468 00000 n +0000010573 00000 n +0000010678 00000 n +0000010783 00000 n +0000010888 00000 n +0000010993 00000 n +0000011098 00000 n +0000011203 00000 n +0000011308 00000 n +0000011413 00000 n +0000011518 00000 n +0000011623 00000 n +0000011728 00000 n +0000011833 00000 n +0000011937 00000 n +0000012043 00000 n +0000012149 00000 n +0000012255 00000 n +0000012360 00000 n +0000012463 00000 n +0000012567 00000 n +0000012913 00000 n +0000013019 00000 n +0000013125 00000 n +0000013231 00000 n +0000013337 00000 n +0000013443 00000 n +0000013549 00000 n +0000013655 00000 n +0000013761 00000 n +0000013867 00000 n +0000013957 00000 n +0000013991 00000 n +0000014025 00000 n +0000015437 00000 n +0000015486 00000 n +0000015535 00000 n +0000015584 00000 n +0000015633 00000 n +0000015682 00000 n +0000015731 00000 n +0000015780 00000 n +0000015829 00000 n +0000015878 00000 n +0000015927 00000 n +0000015976 00000 n +0000016025 00000 n +0000016074 00000 n +0000016123 00000 n +0000016172 00000 n +0000016221 00000 n +0000016270 00000 n +0000016319 00000 n +0000016368 00000 n +0000016417 00000 n +0000016466 00000 n +0000016515 00000 n +0000016564 00000 n +0000016613 00000 n +0000016662 00000 n +0000016711 00000 n +0000016760 00000 n +0000016809 00000 n +0000016858 00000 n +0000016907 00000 n +0000016956 00000 n +0000017005 00000 n +0000017054 00000 n +0000017103 00000 n +0000017152 00000 n +0000017201 00000 n +0000017250 00000 n +0000017299 00000 n +0000017348 00000 n +0000017397 00000 n +0000017446 00000 n +0000017495 00000 n +0000017544 00000 n +0000017593 00000 n +0000017642 00000 n +0000017691 00000 n +0000017740 00000 n +0000017789 00000 n +0000017838 00000 n +0000017887 00000 n +0000017936 00000 n +0000017985 00000 n +0000018034 00000 n +0000018083 00000 n +0000018132 00000 n +0000018181 00000 n +0000018230 00000 n +0000018279 00000 n +0000018328 00000 n +0000018377 00000 n +0000018426 00000 n +0000018475 00000 n +0000018524 00000 n +0000018573 00000 n +0000018622 00000 n +0000018671 00000 n +0000018720 00000 n +0000018769 00000 n +0000018818 00000 n +0000018867 00000 n +0000018916 00000 n +0000018965 00000 n +0000019014 00000 n +0000019063 00000 n +0000019112 00000 n +0000019161 00000 n +0000019210 00000 n +0000019259 00000 n +0000019308 00000 n +0000019357 00000 n +0000019406 00000 n +0000019455 00000 n +0000019504 00000 n +0000019553 00000 n +0000019602 00000 n +0000019651 00000 n +0000019700 00000 n +0000019749 00000 n +0000019798 00000 n +0000019847 00000 n +0000019896 00000 n +0000019945 00000 n +0000019994 00000 n +0000020043 00000 n +0000020092 00000 n +0000020141 00000 n +0000020190 00000 n +0000020239 00000 n +0000020288 00000 n +0000020337 00000 n +0000020710 00000 n +0000020862 00000 n +0000027212 00000 n +0000027234 00000 n +0000027329 00000 n +0000027431 00000 n +0000027451 00000 n +0000027605 00000 n +0000028254 00000 n +0000028275 00000 n +0000028388 00000 n +0000028567 00000 n +0000028588 00000 n +0000028728 00000 n +0000029492 00000 n +0000029513 00000 n +0000029626 00000 n +0000029810 00000 n +0000029831 00000 n +0000029980 00000 n +0000031171 00000 n +0000031193 00000 n +0000031315 00000 n +0000032344 00000 n +0000032365 00000 n +0000032505 00000 n +0000033304 00000 n +0000033325 00000 n +0000033465 00000 n +0000034257 00000 n +0000034278 00000 n +0000034418 00000 n +0000035234 00000 n +0000035255 00000 n +0000035404 00000 n +0000036307 00000 n +0000036328 00000 n +0000036459 00000 n +0000037251 00000 n +0000037272 00000 n +0000037412 00000 n +0000038146 00000 n +0000038167 00000 n +0000038307 00000 n +0000039091 00000 n +0000039112 00000 n +0000039243 00000 n +0000040107 00000 n +0000040128 00000 n +0000040259 00000 n +0000040947 00000 n +0000040968 00000 n +0000041108 00000 n +0000041848 00000 n +0000041869 00000 n +0000042000 00000 n +0000042812 00000 n +0000042833 00000 n +0000042973 00000 n +0000043779 00000 n +0000043800 00000 n +0000043931 00000 n +0000044580 00000 n +0000044601 00000 n +0000044732 00000 n +0000045355 00000 n +0000045376 00000 n +0000045507 00000 n +0000046232 00000 n +0000046253 00000 n +0000046384 00000 n +0000047177 00000 n +0000047198 00000 n +0000047329 00000 n +0000048187 00000 n +0000048208 00000 n +0000048339 00000 n +0000048829 00000 n +0000048850 00000 n +0000048990 00000 n +0000050145 00000 n +0000050167 00000 n +0000050316 00000 n +0000051374 00000 n +0000051395 00000 n +0000051526 00000 n +0000052409 00000 n +0000052430 00000 n +0000052561 00000 n +0000053481 00000 n +0000053502 00000 n +0000053642 00000 n +0000054470 00000 n +0000054491 00000 n +0000054640 00000 n +0000055817 00000 n +0000055839 00000 n +0000055970 00000 n +0000056611 00000 n +0000056632 00000 n +0000056745 00000 n +0000056965 00000 n +0000056986 00000 n +0000057140 00000 n +0000059530 00000 n +0000059552 00000 n +0000059707 00000 n +0000062534 00000 n +0000062556 00000 n +0000062702 00000 n +0000063638 00000 n +0000063659 00000 n +0000063772 00000 n +0000063937 00000 n +0000063957 00000 n +0000064012 00000 n +0000064117 00000 n +0000064261 00000 n +0000064367 00000 n +0000064476 00000 n +0000064625 00000 n +0000064735 00000 n +0000064842 00000 n +0000064989 00000 n +0000065089 00000 n +0000065200 00000 n +0000065350 00000 n +0000065497 00000 n +0000065608 00000 n +0000065720 00000 n +0000065881 00000 n +0000065993 00000 n +0000066106 00000 n +0000066275 00000 n +0000066395 00000 n +0000066516 00000 n +0000066683 00000 n +0000066801 00000 n +0000066920 00000 n +0000067088 00000 n +0000067207 00000 n +0000067340 00000 n +0000067473 00000 n +0000067604 00000 n +0000067723 00000 n +0000067893 00000 n +0000068014 00000 n +0000068136 00000 n +0000068303 00000 n +0000068421 00000 n +0000068540 00000 n +0000068705 00000 n +0000068821 00000 n +0000068938 00000 n +0000069106 00000 n +0000069225 00000 n +0000069345 00000 n +0000069513 00000 n +0000069632 00000 n +0000069752 00000 n +0000069920 00000 n +0000070039 00000 n +0000070159 00000 n +0000070327 00000 n +0000070446 00000 n +0000070566 00000 n +0000070734 00000 n +0000070853 00000 n +0000070973 00000 n +0000071125 00000 n +0000071241 00000 n +0000071361 00000 n +0000071497 00000 n +0000071642 00000 n +0000071766 00000 n +0000071900 00000 n +0000072044 00000 n +0000072156 00000 n +0000072321 00000 n +0000072441 00000 n +0000072576 00000 n +0000072704 00000 n +0000072842 00000 n +0000072975 00000 n +0000073100 00000 n +0000073226 00000 n +0000073361 00000 n +0000073495 00000 n +0000073621 00000 n +0000073761 00000 n +0000073899 00000 n +0000074038 00000 n +0000074172 00000 n +0000074309 00000 n +0000074446 00000 n +0000074578 00000 n +0000074709 00000 n +0000074848 00000 n +0000074985 00000 n +0000075096 00000 n +0000075251 00000 n +0000075385 00000 n +0000075516 00000 n +0000075657 00000 n +0000075775 00000 n +0000075934 00000 n +0000076062 00000 n +0000076205 00000 n +0000076351 00000 n +0000076485 00000 n +0000076624 00000 n +0000076782 00000 n +0000076926 00000 n +0000077078 00000 n +0000077207 00000 n +0000077327 00000 n +trailer +<> +startxref +77555 +%%EOF diff --git a/doc/ipp.shtml b/doc/ipp.shtml new file mode 100644 index 0000000000..2c4d57f7aa --- /dev/null +++ b/doc/ipp.shtml @@ -0,0 +1,1767 @@ + + + + + + CUPS Implementation of IPP + + + +

Scope

+ +

Identification

+ +

This document provides an overview of the Internet Printing Protocol +("IPP") version 1.1 as implemented in the Common UNIX Printing System +("CUPS") Version 1.1. + + + +

Document Overview

+ +

This document is organized into the following sections: + +

+ + + +

Overview

+ +

CUPS 1.1 implements IPP/1.1 and the operations and attributes +defined in the "IPP: Job and Printer Set Operations", +"IPP/1.1: Output-bin Attribute Extension", and "IPP/1.1: finishings +'fold',' trim', and 'bale' attribute values extension" specifications. + +

CUPS also provides 12 new operations and many new attributes to +support multiple IPP printers and printer classes on a single host. + +

IPP URIs

+ +

CUPS supports both the "http" and "ipp" method names. The following +resource names are used: + +

+ +
method://hostname:port/ + +
Can be used for all "get" operations. + +
method://hostname:port/admin + +
Used for all administrative operations. + +
method://hostname:port/classes/name + +
Specifies a printer class. + +
method://hostname:port/jobs/id + +
Specifies a job. + +
method://hostname:port/printers/name + +
Specifies a printer. + +
+ +

So a typical printer URI would be "ipp://foo.bar.com/printers/LaserJet". + +

In addition, the CUPS server also supports normal browser access to +"method://hostname:port/admin/", "method://hostname:port/classes/", +"method://hostname:port/jobs/", and "method://hostname:port/printers/" +to view and manage resources on the server dynamically. + +

CUPS IPP Operations

+ +

CUPS provides 12 extension operations in addition to most of the +standard IPP and registered extension operations: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operation NameCUPSCodeBrief Description
Print-Job1.00x0002Print a file.
Validate-Job1.00x0004Validate job attributes.
Create-Job1.10x0005Create a print job.
Send-Document1.10x0006Send a file for a print job.
Cancel-Job1.00x0008Cancel a print job.
Get-Job-Attributes1.00x0009Get job attributes.
Get-Jobs1.00x000AGet all jobs.
Get-Printer-Attributes1.00x000BGet printer attributes.
Hold-Job1.10x000CHold a job for printing.
Release-Job1.10x000DRelease a job for printing.
Pause-Printer1.00x0010Pause printing on a printer.
Resume-Printer1.00x0011Resume printing on a printer.
Purge-Jobs1.00x0012Purge all jobs.
Set-Job-Attributes1.10x0014Set attributes for a pending or held job.
CUPS-Get-Default1.00x4001Get the default destination.
CUPS-Get-Printers1.00x4002Get all of the available printers.
CUPS-Add-Printer1.00x4003Add or modify a printer.
CUPS-Delete-Printer1.00x4004Delete a printer.
CUPS-Get-Classes1.00x4005Get all of the available printer classes.
CUPS-Add-Class1.00x4006Add or modify a printer class.
CUPS-Delete-Class1.00x4007Delete a printer class.
CUPS-Accept-Jobs1.00x4008Accept jobs on a printer or printer class.
CUPS-Reject-Jobs1.00x4009Reject jobs on a printer or printer class.
CUPS-Set-Default1.00x400ASet the default destination.
CUPS-Get-Devices1.10x400BGet all of the available devices.
CUPS-Get-PPDs1.10x400CGet all of the available PPDs.
+
+ +

Operations

+ +

The following sections describe the operations supported by CUPS. +In the interest of brevity, operations which use only the standard +IPP attributes are not described. + +

Print-Job Operation

+ +

The Print-Job operation (0x0002) prints a file. + +

Print-Job Request

+ +

The following groups of attributes are supplied as part of the +Print-Job Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

Group 2: Job Template Attributes + +

    + +

    "banner-end" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page that is printed + after any files in the print job. The name of "none" is + reserved to indicate that no banner page should be printed. If + the client does not specify this attribute then the value of + the "banner-end-default" printer object attribute is used. + +

    "banner-start" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page that is printed + before any files in the print job. The name of "none" is + reserved to indicate that no banner page should be printed. If + the client does not specify this attribute then the value of + the "banner-start-default" printer object attribute is used. + +

    Other Job Template Attributes + +

+ +

The Print-Job Request is followed by a file to be printed. + +

Print-Job Response

+ +

The following groups of attributes are send as part of the Print-Job +Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Job Attributes + +

    + +

    Standard Job Attributes + +

+ +

Create-Job Operation

+ +

The Create-Job operation (0x0005) creates a new, empty print job. + +

Create-Job Request

+ +

The following groups of attributes are supplied as part of the +Create-Job Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

Group 2: Job Template Attributes + +

    + +

    "banner-end" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page that is printed + after any files in the print job. The name of "none" is + reserved to indicate that no banner page should be printed. If + the client does not specify this attribute then the value of + the "banner-end-default" printer object attribute is used. + +

    "banner-start" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page that is printed + before any files in the print job. The name of "none" is + reserved to indicate that no banner page should be printed. If + the client does not specify this attribute then the value of + the "banner-start-default" printer object attribute is used. + +

    Standard Job Template Attributes + +

+ +

Create-Job Response

+ +

The following groups of attributes are send as part of the +Create-Job Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Job Attributes + +

    + +

    Standard Job Attributes + +

+ +

Set-Job-Attributes Operation

+ +

The Set-Job-Attributes operation (0x0002) prints a file. + +

Set-Job-Attributes Request

+ +

The following groups of attributes are supplied as part of the +Set-Job-Attributes Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri) and "job-id" (integer) +

    OR +

    "job-uri": + +

    The client MUST supply a URI for the specified printer and + a job ID number, or the job URI. + +

+ +

Group 2: Job Template Attributes + +

    + +

    "job-printer-uri" (uri): + +

    The client OPTIONALLY supplies the URI of a new printer + destination for the job. The new URI MUST utilize the same + IPP server (i.e. you cannot move the job to a different server). + +

    NOTE: This attribute is defined to be READ-ONLY in the + current IETF specification for this operation. CUPS allows the + "job-printer-uri" attribute to be changed, which makes the CUPS + implementation non-conforming for this particular operation. + +

    "banner-end" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page that is printed + after any files in the print job. The name of "none" is + reserved to indicate that no banner page should be printed. If + the client does not specify this attribute then the value of + the "banner-end-default" printer object attribute is used. + +

    "banner-start" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page that is printed + before any files in the print job. The name of "none" is + reserved to indicate that no banner page should be printed. If + the client does not specify this attribute then the value of + the "banner-start-default" printer object attribute is used. + +

    Other Job Template Attributes + +

+ +

Set-Job-Attributes Response

+ +

The following groups of attributes are send as part of the Set-Job-Attributes +Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Get-Default Operation

+ +

The CUPS-Get-Default operation (0x4001) returns the default printer +URI and attributes. + +

CUPS-Get-Default Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Default Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names + and/or attribute group names in whose values the requester is + interested. If the client omits this attribute, the server + responds as if this attribute had been supplied with a value of + 'all'. + +

+ +

CUPS-Get-Default Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Default Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    The set of requested attributes and their current values. + +

+ +

CUPS-Get-Printers Operation

+ +

The CUPS-Get-Printers operation (0x4002) returns the printer +attributes for every printer known to the system. This may include +printers that are not served directly by the server. + +

CUPS-Get-Printers Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Printers Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the + number of printers that are returned. + +

    "printer-info" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printers are returned. + +

    "printer-location" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printers are returned. + +

    "printer-type" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type enumeration to + select which printers are returned. + +

    "printer-type-mask" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type mask + enumeration to select which bits are used in the "printer-type" + attribute. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names + and/or attribute group names in whose values the requester is + interested. If the client omits this attribute, the server + responds as if this attribute had been supplied with a value of + 'all'. + +

+ +

CUPS-Get-Printers Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Printers Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    The set of requested attributes and their current values for + each printer. + +

+ +

CUPS-Add-Printer Operation

+ +

The CUPS-Add-Printer operation (0x4003) adds a new printer or +modifies an existing printer on the system. + +

CUPS-Add-Printer Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Add-Printer Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    "banner-end-default" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page name that is + printed after files in a job. The reserved name "none" is used to + specify that no banner page should be printed. + +

    "banner-start-default" (name(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a banner page name that is + printed before files in a job. The reserved name "none" is used to + specify that no banner page should be printed. + +

    "device-uri" (uri): + +

    The client OPTIONALLY supplies a device URI for the + specified printer. + +

    "ppd-name" (name(127)): + +

    The client OPTIONALLY supplies a PPD name for the specified + printer. + +

    "printer-is-accepting-jobs" (boolean): + +

    The client OPTIONALLY supplies this boolean attribute + indicating whether or not the printer object should accept new jobs. + +

    "printer-info" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating the + printer information string. + +

    "printer-location" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual location of the printer. + +

    "printer-more-info" (uri): + +

    The client OPTIONALLY supplies this attribute indicating a + URI for additional printer information. + +

    "printer-state" (type2 enum): + +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the printer. Only the "idle" and "stopped" + enumerations are recognized. + +

    "printer-state-message" (text(MAX)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual reason for the current printer state. + +

    "requesting-user-name-allowed" (1setof name(127)) +

    OR +

    "requesting-user-name-denied" (1setof name(127)): + +

    The client OPTIONALLY supplies one of these attributes to + specify an access control list for incoming print jobs. The + special name "ALLUSERS" is reserved to indicate that all users + are allowed or denied. + +

+ +

The CUPS-Add-Printer Request can optionally be followed by a PPD +file or System V interface script to be used for the printer. The +"ppd-name" attribute overrides any file that is attached to the end of +the request with a local CUPS PPD file. + +

CUPS-Add-Printer Response

+ +

The following groups of attributes are send as part of the +CUPS-Add-Printer Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Delete-Printer Operation

+ +

The CUPS-Delete-Printer operation (0x4004) removes an existing +printer from the system. + +

CUPS-Delete-Printer Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Delete-Printer Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer. + +

+ +

CUPS-Delete-Printer Response

+ +

The following groups of attributes are send as part of the +CUPS-Delete-Printer Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Get-Classes Operation

+ +

The CUPS-Get-Classes operation (0x4005) returns the printer +attributes for every printer class known to the system. This may +include printer classes that are not served directly by the server. + +

CUPS-Get-Classes Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Classes Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the + number of printer classes that are returned. + +

    "printer-info" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printer classes are returned. + +

    "printer-location" (text(127)): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies this attribute to + select which printer classes are returned. + +

    "printer-type" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type enumeration to + select which printer classes are returned. + +

    "printer-type-mask" (type2 enum): + +

    (CUPS 1.1 and higher) + +

    The client OPTIONALLY supplies a printer type mask + enumeration to select which bits are used in the "printer-type" + attribute. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names + and/or attribute group names in whose values the requester is + interested. If the client omits this attribute, the server responds as + if this attribute had been supplied with a value of 'all'. + +

+ +

CUPS-Get-Classes Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Classes Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Printer Class Object Attributes + +

    + +

    The set of requested attributes and their current values for + each printer class. + +

+ +

CUPS-Add-Class Operation

+ +

The CUPS-Add-Class operation (0x4006) adds a new printer class or +modifies and existing printer class on the system. + +

CUPS-Add-Class Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Add-Class Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer class. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    "member-uris" (1setof uri): + +

    The client OPTIONALLY supplies the "member-uris" set + specifying the printers and printer classes that are part of the class. + +

    "printer-is-accepting-jobs" (boolean): + +

    The client OPTIONALLY supplies this boolean attribute + indicating whether or not the printer object should accept new jobs. + +

    "printer-info" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating the + printer information string. + +

    "printer-location" (text(127)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual location of the printer. + +

    "printer-more-info" (uri): + +

    The client OPTIONALLY supplies this attribute indicating a + URI for additional printer information. + +

    "printer-state" (type2 enum): + +

    The client OPTIONALLY supplies this attribute indicating the + initial/current state of the printer. Only the "idle" and "stopped" + enumerations are recognized. + +

    "printer-state-message" (text(MAX)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual reason for the current printer state. + +

    "requesting-user-name-allowed" (1setof name(127)) +

    OR +

    "requesting-user-name-denied" (1setof name(127)): + +

    The client OPTIONALLY supplies one of these attributes to + specify an access control list for incoming print jobs. The + special name "ALLUSERS" is reserved to indicate that all users + are allowed or denied. + +

+ +

CUPS-Add-Class Response

+ +

The following groups of attributes are send as part of the CUPS-Add-Class Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Delete-Class Operation

+ +

The CUPS-Delete-Class operation (0x4007) removes an existing printer +class from the system. + +

CUPS-Delete-Class Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Delete-Class Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer class. + +

+ +

CUPS-Delete-Class Response

+ +

The following groups of attributes are send as part of the +CUPS-Delete-Class Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Accept-Jobs Operation

+ +

The CUPS-Accept-Jobs operation (0x4008) sets the +"printer-is-accepting-jobs" attribute to true for the specified printer +or printer class. + +

CUPS-Accept-Jobs Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Accept-Jobs Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer or printer class. + +

+ +

CUPS-Accept-Jobs Response

+ +

The following groups of attributes are send as part of the +CUPS-Accept-Jobs Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Reject-Jobs Operation

+ +

The CUPS-Reject-Jobs operation (0x4009) sets +the"printer-is-accepting-jobs" attribute to false for the specified +printer or printer class. + +

CUPS-Reject-Jobs Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Reject-Jobs Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer or printer class. + +

+ +

Group 2: Printer Object Attributes + +

    + +

    "printer-state-message" (text(MAX)): + +

    The client OPTIONALLY supplies this attribute indicating a + textual reason for the current printer state. + +

+ +

CUPS-Reject-Jobs Response

+ +

The following groups of attributes are send as part of the +CUPS-Reject-Jobs Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Set-Default Operation

+ +

The CUPS-Set-Default operation (0x400A) sets the default printer +destination for all clients when a resource name of "/printers" is +specified. + +

CUPS-Set-Default Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Set-Default Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "printer-uri" (uri): + +

    The client MUST supply a URI for the specified printer or + printer class. + +

+ +

CUPS-Set-Default Response

+ +

The following groups of attributes are send as part of the +CUPS-Set-Default Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

CUPS-Get-Devices Operation

+ +

The CUPS-Get-Devices operation (0x400B) returns all of the supported +device-uri's for the server (CUPS 1.1 and higher). + +

CUPS-Get-Devices Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-Devices Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "device-class" (type1 keyword): + +

    The client OPTIONALLY supplies a device class keyword to select + which devices are returned. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the number of + devices that are returned. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'. + +

+ +

CUPS-Get-Devices Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Devices Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Device Object Attributes + +

    + +

    The set of requested attributes and their current values for + each device. + +

+ +

CUPS-Get-PPDs Operation

+ +

The CUPS-Get-PPDs operation (0x400C) returns all of the locally +available PPD files on the system (CUPS 1.1 and higher). + +

CUPS-Get-PPDs Request

+ +

The following groups of attributes are supplied as part of the +CUPS-Get-PPDs Request: + +

Group 1: Operation Attributes + +

    + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.1 of the IPP Model and + Semantics document. + +

    "limit" (integer (1:MAX)): + +

    The client OPTIONALLY supplies this attribute limiting the number of + PPDs that are returned. + +

    "ppd-make" (text(127)): + +

    The client OPTIONALLY supplies a printer manufacturer to select + which PPDs are returned. + +

    "requested-attributes" (1setOf keyword) : + +

    The client OPTIONALLY supplies a set of attribute names and/or + attribute group names in whose values the requester is interested. If + the client omits this attribute, the server responds as if this + attribute had been supplied with a value of 'all'. + +

+ +

CUPS-Get-Classes Response

+ +

The following groups of attributes are send as part of the +CUPS-Get-Classes Response: + +

Group 1: Operation Attributes + +

    + +

    Status Message: + +

    The standard response status message. + +

    Natural Language and Character Set: + +

    The "attributes-charset" and "attributes-natural-language" + attributes as described in section 3.1.4.2 of the IPP Model and + Semantics document. + +

+ +

Group 2: Printer Class Object Attributes + +

    + +

    The set of requested attributes and their current values for each + printer class. + +

+ +

Attributes

+ +

CUPS provides many extension attributes to support multiple devices, +PPD files, standard job filters, printers, and printer classes. + +

Device Attributes

+ +

Device attributes are returned by the CUPS-Get-Devices operation and +enumerate all of the available hardware devices and network protocols +that are supported by the server. + +

device-class (type2 keyword)

+ +

The device-class attribute specifies the class of device and can be +one of the following: + +

    + +
  • "file" - a disk file. + +
  • "direct" - a parallel or fixed-rate serial data port, + currently used for Centronics, IEEE-1284, and USB printer + ports. + +
  • "serial" - a variable-rate serial port. + +
  • "network" - a network connection, typically via AppSocket, + HTTP, IPP, LPD, or SMB/CIFS protocols. + +
+ +

device-info (text(127))

+ +

The device-info attribute specifies a human-readable string describing +the device, e.g. "EPP Parallel Port #1". + +

device-make-and-model (text(127))

+ +

The device-makr-and-model attribute specifies a device +identification string provided by the printer connected to the device. +If the device or printer does not support identification then this +attribute contains the string "unknown". + +

device-uri (uri)

+ +

The device-uri attribute specifies a unique identifier for the +device. The actual format of the device-uri string depends on the value +of the device-class attribute: + +

    + +
  • "file" - The device-uri will be of the form + "file:/path/to/filename". + +
  • "direct" - The device-uri will be of the form + "method:/dev/filename", where method may be "parallel" or "usb" + in the current implementation. + +
  • "serial" - The device-uri will be of the form + "serial:/dev/filename?baud=value+parity=value+flow=value". + The parity value can be one of "none", "even", or "odd". + The flow value can be one of "none", "soft" (XON/XOFF + handshaking), or "hard" (CTS/RTS handshaking). + +

    The URI returned by CUPS-Get-Devices will contain the + maximum baud rate supported by the device and the best + type of flow control available ("soft" or "hard"). + +

  • "network" - The device-uri will be of the form + "method://[username:password@]hostname[:port]/[resource]", + where method may be "http", "ipp", "lpd", "smb", or + "socket" in the current implementation. + +

    The URI returned by CUPS-Get-Devices will only contain + the method name followed by two slashes ("method://"). + It is up to the client application to add the appropriate + host and other information when adding a new printer. + +

    The URI returned by Get-Printer-Attributes and + CUPS-Get-Printers has any username and password information + stripped; the information is still stored and used by the + server internally to perform any needed authentication. + +

+ +

Job Template Attributes

+ +

banner-end (name(127))

+ +

(CUPS 1.1 and higher) + +

The banner-end attribute specifies a banner file that is printed after +any files in a job. The reserved value of "none" disables banner printing. +The default value is stored in the banner-end-default attribute. + +

banner-start (name(127))

+ +

(CUPS 1.1 and higher) + +

The banner-end attribute specifies a banner file that is printed before +any files in a job. The reserved value of "none" disables banner printing. +The default value is stored in the banner-start-default attribute. + +

blackplot (boolean)

+ +

The blackplot attribute specifies whether HP-GL/2 plot files should be +rendered entirely in black ink (blackplot=true) or using the colors and shades +specified in the file (blackplot=false). The default value is false. + +

brightness (integer(0:200))

+ +

The brightness attribute specifies the overall brightness of the printed +output in percent. A brightness of 100 is normal, while 200 is twice as +bright and 50 is half as bright. The default value is 100. + +

Brightness is applied to the Cyan, Magenta, Yellow, and Black values using +the function "f(x) = brightness / 100 * x". + +

columns (integer(1:4))

+ +

The columns attribute specifies the number of columns to generate when +printing text files. The default value is 1. + +

cpi (type2 enum)

+ +

The cpi attribute specifies the number of characters per inch when +printing text files. Only the values 10, 12, and 17 are currently +supported. The default value is 10. + +

fitplot (boolean)

+ +

The fitplot attribute specifies whether to scale HP-GL/2 plot files to +fit on the selected media (fitplot=true) or use the physical scale specified +in the plot file (fitplot=false). The default value is false. + +

gamma (integer(1:10000))

+ +

The gamma attribute specifies the luminance correction for the output. +A value of 1000 specifies no correction, while values of 2000 and 500 will +generate lighter and darker output, respectively. The default value is +1000. + +

Gamma is applied to the Red, Green, and Blue values (or luminance for +grayscale output) using the function "f(x) = x(1000/gamma)". + +

hue (integer(-180:180))

+ +

The hue attribute specifies a color hue rotation when printing image +files. The default value is 0. + +

lpi (type2 enum)

+ +

The lpi attribute specifies the number of lines per inch when +printing text files. Only the values 6 and 8 are currently supported. +The default value is 6. + +

page-bottom (integer(0:MAX))

+ +

The page-bottom attribute specifies the bottom margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

page-left (integer(0:MAX))

+ +

The page-left attribute specifies the left margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

page-right (integer(0:MAX))

+ +

The page-right attribute specifies the right margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

page-set (type2 keyword)

+ +

The page-set attribute specifies which pages to print in a file. The +supported keywords are "all", "even", and "odd". The default value is +"all". + +

page-top (integer(0:MAX))

+ +

The page-top attribute specifies the top margin in points (72 points +equals 1 inch). The default value is the device physical margin. + +

penwidth (integer(0:MAX))

+ +

The penwidth attribute specifies the default pen width in micrometers +when printing HP-GL/2 plot files. The default value is 1000 (1 millimeter). + +

ppi (integer(1:MAX))

+ +

The ppi attribute specifies the resolution of an image file in pixels +per inch. The default value is the resolution included with the file or +128 if no resolution information is available. + +

prettyprint (boolean)

+ +

The prettyprint attribute specifies whether text files should be printed +with a shaded header and keyword highlighting (prettyprint=true) or without +additional formatting (prettyprint=false). The default value is false. + +

saturation (integer(0:200))

+ +

The saturation attribute specifies the color saturation when +printing image files. A saturation of 100 is normal, while values of 50 +and 200 will be half and twice as colorful, respectively. The default +value is 100. + +

scaling (integer(1:1000))

+ +

The scaling attribute specifies the scaling of image files with +respect to the selected media. A value of 100 specifies that the image +file should fit 100% of the page, or as much as possible given the +image dimensions. The default value is unspecified. + +

The scaling attribute overrides the ppi attribute if specified. + +

wrap (boolean)

+ +

The wrap attribute specifies whether long lines should be wrapped +(wrap=true) or not (wrap=false) when printing text files. The default +value is true. + +

PPD Attributes

+ +

ppd-natural-language (naturalLanguage)

+ +

The ppd-natural-language attribute specifies the language encoding +of the PPD file (the LanguageVersion attribute in the PPD file). If the +language is unknown or undefined then "en" (English) is assumed. + +

ppd-make (text(127))

+ +

The ppd-make attribute specifies the manufacturer of the printer +(the Manufacturer attribute in the PPD file). If the manufacturer +is not specified in the PPD file then an educated guess is made using +the NickName attribute in the PPD file. + +

ppd-make-and-model (text(127))

+ +

The ppd-make-and-model attribute specifies the manufacturer and model +name of the PPD file (the NickName attribute in the PPD file). If the +make and model is not specified in the PPD file then the ModelName or +ShortNickName attributes are used instead. + +

ppd-name (name(255))

+ +

The ppd-name attribute specifies the PPD filename on the server +relative to the model directory. The forward slash (/) is used to +delineate directories. + +

Printer Attributes

+ +

banner-end-default (name(127))

+ +

(CUPS 1.1 and higher) + +

The banner-end-default attribute specifies the default banner file to +print after all files in a job. The value "none" specifies that no banner +should be printed. + +

banner-start-default (name(127))

+ +

(CUPS 1.1 and higher) + +

The banner-start-default attribute specifies the default banner file to +print before all files in a job. The value "none" specifies that no banner +should be printed. + +

banner-supported (1setof name(127))

+ +

(CUPS 1.1 and higher) + +

The banner-supported attribute specifies the available banner files. +There will always be at least one banner file available called "none". + +

printer-type (type2 enum)

+ +

The printer-type attribute specifies printer type and capability bits for +the printer or class. The default value is computed from internal state +information and the PPD file for the printer. The following bits are defined: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitDescription
0x00000001Is a printer class.
0x00000002Is a remote destination.
0x00000004Can print in black.
0x00000008Can print in color.
0x00000010Can print on both sides of the page in hardware.
0x00000020Can staple output.
0x00000040Can do fast copies in hardware.
0x00000080Can do fast copy collation in hardware.
0x00000100Can punch output.
0x00000200Can cover output.
0x00000400Can bind output.
0x00000800Can sort output.
0x00001000Can handle media up to US-Legal/A4.
0x00002000Can handle media from US-Legal/A4 to ISO-C/A2.
0x00004000Can handle media larger than ISO-C/A2.
0x00008000Can handle user-defined media sizes.
0x00010000Is an implicit (server-generated) class.
+ +

printer-type-mask (type2 enum)

+ +

(CUPS 1.1 and higher) + +

The printer-type-mask attribute is used to choose printers or classes with +the CUPS-Get-Printers and CUPS-Get-Classes operations. The bits are defined +identically to the printer-type attribute and default to all 1's. + +

requesting-user-name-allowed (1setof name(127))

+ +

The requesting-user-name-allowed attribute lists all of the users that are +allowed to access a printer or class. Either this attribute or the +requesting-user-name-denied attribute will be defined, but not both. + +

The special name "ALLUSERS" is reserved to indicate that all users +allowed. + +

requesting-user-name-denied (1setof name(127))

+ +

The requesting-user-name-denied attribute lists all of the users that are +not allowed to access a printer or class. Either this attribute or the +requesting-user-name-allowed attribute will be defined, but not both. + +

The special name "ALLUSERS" is reserved to indicate that all users +denied. + +

Printer Class Attributes

+ +

member-names (1setof name(127))

+ +

The member-names attribute specifies each of the printer-name attributes of +the member printers and classes. Each name corresponds to the same element of +the member-uris attribute. + +

member-uris (1setof uri)

+ +

The member-uris attribute specifies each of the printer-uri attributes of +the member printers and classes. Each URI corresponds to the same element of +the member-names attribute. + + + + + diff --git a/doc/overview.html b/doc/overview.html new file mode 100644 index 0000000000..8a711ba042 --- /dev/null +++ b/doc/overview.html @@ -0,0 +1,292 @@ + + + + An Overview of the Common UNIX Printing System + + + + + + + + +

An Overview of the
+ Common UNIX Printing System

+ +

October 4, 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. Printer classes are collections of printers. Jobs +sent to a class are forwarded to the first available printer in the +class, round-robin fashion. + +

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 cupsFilter entries in the printer PPD +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. +Each filter has a relative cost associated with it, and the filtering +algorithm chooses the set of filters that will convert the file to the +needed format with the lowest total "cost". + +

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, +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 GNU General Public License +which means that it is basically free except for binary-only +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..6986d8dfc8 Binary files /dev/null and b/doc/overview.pdf differ diff --git a/doc/references.shtml b/doc/references.shtml new file mode 100644 index 0000000000..31446e6f5d --- /dev/null +++ b/doc/references.shtml @@ -0,0 +1,39 @@ +

References

+ +

CUPS Documentation

+ +

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

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

Other Documents

+ +

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

    +
  • Adobe PostScript Printer Description File Format Specification, + Version 4.3. +
  • Adobe PostScript Language Reference, Third Edition. +
  • IPP: Job and Printer Set Operations +
  • IPP/1.1: Encoding and Transport +
  • IPP/1.1: Implementers Guide +
  • IPP/1.1: Model and Semantics +
  • RFC 1179, Line Printer Daemon Protocol +
  • RFC 2567, Design Goals for an Internet Printing Protocol +
  • RFC 2568, Rationale for the Structure of the Model and Protocol + for the Internet Printing Protocol +
  • RFC 2569, Mapping between LPD and IPP Protocols +
  • RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1 +
  • RFC 2617, HTTP Authentication: Basic and Digest Access + Authentication +
diff --git a/doc/sam.html b/doc/sam.html new file mode 100644 index 0000000000..aab53c474b --- /dev/null +++ b/doc/sam.html @@ -0,0 +1,934 @@ + + + +CUPS Software Administrators Manual + + + + + + + +

+

CUPS Software Administrators Manual


+CUPS-SAM-1.1
+Easy Software Products
+Copyright 1997-2000, 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 + +A - Using CUPS with SAMBA + +
+

Preface

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

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 5.50) and an image file RIP that +is 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
  • +
  • A - Using CUPS with SAMBA
  • +
+

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
+
smb://[username:password@]workgroup/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.

+

A - Using CUPS with SAMBA

+

This appendix describes how to use CUPS with SAMBA.

+

What is SAMBA?

+

In case you haven't heard of SAMBA, it is basically a software +package that allows you to configure your UNIX system as a Windows file +and printer server. It also allows you to access files and printers on +a Windows system. Like CUPS, SAMBA is free software.

+

SAMBA version 2.0.6 is the first release of SAMBA that supports +CUPS. You can download SAMBA from:

+

http://www.samba.org +

+

How Do I Configure SAMBA for CUPS?

+

To configure SAMBA for CUPS, edit the smb.conf file and +replace the existing printing commands and options with the line:

+
    +
    +printing = cups
    +
    +
+

That's all there is to it! Remote users will now be able to browse +and print to printers on your system.

+

How Do I Configure CUPS for SAMBA?

+

To configure CUPS for SAMBA, run the following command:

+
    +
    +% ln -s `which smbspool` /var/cups/backend/smb ENTER
    +
    +
+

The smbspool program is provided with SAMBA starting +with SAMBA 2.0.6. Once you have made the link you can use the smb + method in the device URI for your printers:

+
    +
    +% lpadmin -p printer -v smb://hostname/printer ... ENTER
    +% lpadmin -p printer -v smb://workgroup/hostname/printer ... ENTER
    +
    +
+

The second form only needs to be used if the Windows system is in a +different workgroup.

+ + diff --git a/doc/sam.pdf b/doc/sam.pdf new file mode 100644 index 0000000000..05f453e1b9 --- /dev/null +++ b/doc/sam.pdf @@ -0,0 +1,960 @@ +%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[12 0 R +]endobj +14 0 obj<>endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj<>endobj +18 0 obj<>endobj +19 0 obj[14 0 R +16 0 R +18 0 R +]endobj +20 0 obj<>endobj +21 0 obj<>endobj +22 0 obj[21 0 R +]endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj[24 0 R +]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[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 +]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[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 +]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<>stream +xÚìÏsë8rÇIŠºÌ‰öŒî´üt§çyšÝ­ÚJñÙfvçÖ$ÁÊ!•S*Ç6•üÿ±~X"H€èn$è5¦jêÙE|ˆÆ·@ƒúÇOßòýÛßò?=å¿ýžÿçÿô,~*ÅOÿÈÛÿù×?þøÛï¿ÿºÏÿü—_Ÿò§§§·kýñõ¥ù÷¯|­ÿöœþº?•ßNå÷SùË©¼œÊ¿žÊ¿üÇ×?òÿýŸÿû¯¯ÿ–ÿíÛ׿ç‡oß¾>ÃKþ=ÿãõ§öcøä²+âõi»Ý>ÜËÛ?¶ß_—Î%^¶wY¤*w÷¯ËäOj¤Üöû¸ē‰é½Ü?–KáÂC]о/ëå!"—x[ÎõœE¼r˜ë‰KåÒ!˜¾rÛg޹^òȾü\ÆÕÊÏ3s=GžJRÎÉõ-òVâÃl\ŽuЄõV¾ÌÂ%²( + ‚B¹ü29×$X,0X –€Åƒ %ƒ/° ¬(ÚMÄåÝoÙ9h6×ÄXo`å\ûhò’LÀõ#𡬼sÕÑ,åÏ\M6A!|…gi,A +Ú Ñ ê£s5Ѭåà‹+›— 9Ä`™ãÅ`ž‹,öD.1?V{àÊàŠRç\uD98æY\‰c®}HÙ8媣`Jé++D91WT蚐°ŒÒË TÔ  LÔ‹Š4ðZåªBÃ2t,OãQ ÔxŒsÆq‰±FãzX¢Æ#F,Ï%£FL×]w÷Ûí—×cy>|ðÛa0IwÅ÷_†ƒüxÂ[‡ÿîŠG’þÅ˃ŸßÝuoœ*=[ í,¸ö~ºªÛk[ça=xì.Bú±àæØ\ìPƒ–.Î$[q¹¸¡==·aMJ&³»XéԜ.K™\¬@ž› É貘ÇUùÑv‡]¶cqeSÙà՛eN¤ܯjؤ½s’  ®|²¡ÅϼJé\Í Xd°˜ÎEùØÍÉÜZ9ƹfÂ"‚­¨\Õ FÈ1ŒȕυEÛи'’ –Y¹0p7ñú¥uZj+Cg‘¼c,Òé« …«rÎX•½ÅÍÁ‘jÄ¥{.B J<—°ÒlKÃ7D=Ì:¸ÎåÛÁÉ %i=•œkˆàBf½ .Ú`Ø`¹Š¹2O”,Á W­Ç’ó ìÍПR4q‡ãÚa…„–¤8®´&1Š«žÙ#3ì€á«aÚz/8 [c¸²0Dƒ¢õ ‚«æfóuXiæ*B J‡íÌ\Y OjOjäªÃê.d‡%F®"°îBú°ÒĕÖ]È'½1p5Á¸dZ“RW\wá¢ÄÄÀ•6ºÐRVŽr‰» 7æw£\u€Ý…[FJG¹*OŠ…²¢d”+ (2$*ÇVå'ÆB ÃRåÓ©¹Z’ Wå“s! q5ÂÀÚÛ=W¢È£­ÔrAˆ"v@;-W¨jàLi­ã¡ªnè¯t\5-4”=Ùí§ž±¿ÿ.Ï´’T¹Æúù=¾aÀ +¢6(®–KH·Kh%ºÖRÕÓbQ®•–ër›®Îa‡Àà ¯Çé¹ £^ >ÜÌіœáµCrí´\MçùÖ 1£$UsÑys¥Z®³í%·NH)}¢æÊ‰Îkœ+ÑsÝ´BPf=ègŒàp‡åz7.×MÛk¼b”¾Tq5ÔÊÀµÑrÝD° ¬•T؇ô¹WŠçZ鹊÷G”Q&ß V<זByW¤çª/ŸÕPÌ1PRWF4C#×NËu¾×úü+ü’QØV +.A5C#WªçڟòáªÕr[¬àª©fhäŠõ\盽§5Rì•K,×êZ[Éu6Ž;êÊ12BªWNZ,×:{—'%WG¤(³ÔgO@• ž«x j®Š5K5†ˆëWC6Ãq®ZÂp ÖbI…Ó5 ÊFÒâ¹Ä»Y¨¹®&EZ,ip-â\9%pžê¹*֚Nè(; +\n£á¬5;c+\ŒôÅq®æ" +®K‰kvª‰@“¤¥pµ¥×qgéB™ÐdcMãº(½Ž«àôWòD@“ë¢ô:®Œ3¾êÙwCÅuQz WÍÛÃÈ0’ ¤h#!r]”^ÃUðûMÏ%s Æð2r•^Õñ6g +ÌÃ’lì¨\g¥Ws5Ì]Œ +㘁´¶ÑR¹ÎJ¯æ½ØER2WÁ^f®“Ò«¹rfæŽÀ8f DQ)ëd݅~^¹e¢IàkSYŽ­\§Öç*®³Ý Fȑ#š ”(ªT?º²k ±ÌukDŸ+?krN7Ä="àVÌµë>š>h¸Þ;а›‚]†Yw¹k6+IlºŠšô¸ Wuáiè†X!dr¸Ñ˜ÄjøCýsȵèÝJ´§•¸rŽlH[âã‹:\…’K\[°'¢@Ø¢C­I¤€]Ÿ«VrU×Ê=öEèà£ÃDïû¯´ùÖṌŸêsí¯#èùVž«áxåÛ-â;^WÈ\OÌɱonn0¾d=äª\ÝT”‚lˆ{ó€¼0ÚT¹WWojò$ ð\{–l lbÕ¹.¶*qeÝKž„‰×ñÒáÊY²Ñ˜×Ó{Šyq—KΈÚ{ÈhzªX¯üPy8Å:F—« »òúh9ÔNþnï5ùÒ*¹Ä€+“,¯ñª è¨Wo'ÍéŧñýGH©\SßËy°†ÇeŽæãvQ°2Ÿ,’+çEQÁse¼(*t.a#‡s5–r*W͍çª>š^¸ +vt6מ͕4™¿peM/\œ¥ùp‰'óg®úÃÉ<–k2ߝÎ-‡͋ó·•Ü:\[æ»uîªßFwÒ²ßmµwpœOm›.Ò,²Î-ï\·u›þà,•\×FÍÕI¿\¹r¶ûRãkT§×ćk¥äjÔûËÛ}©4fÜkbÄኔ\¹z߁¿h£¶W]nj¯‰;×NÁU UPn9Ár­4áËNŕr¸RW6|ŒŽ¹Î«Ëë51áp%C®wшﲫÝÊ-§h®š+Vqõó¡¸g¯r~ô'/ÙÅlp\ëQ®Ó¿^òHjÁZv,¥Šk£tEr<Џ¨ëdÞ7ÛnlÌ\—᯻?"éx@·‰+×à¢Zr—Ûj{‡àꤥÈ]|Ëíé71âp .’7.y<€ +£®[‘"K~­lâŽÃÕ¿(—óM +-áðì8—Ðpz®”ÃÕ¿¨7RNf™*Œj1\·Ùÿj®˜ÃÕ»¨ðTà¹b\Šã|f.ÅEußÁnßÊ#`ÂÃĞk¨Šã|f.ÝÀT5_ŽÜp ×^­óŠã|®áE…ÒÁ&ŒJ[=Ì®9·r‡Çù\Ër¥#Bq­Q\µÚ՚8JqœÁ5¼HËU;â*”ñÆË- é5qxœÁ5¼(S:"×Ã%¢"ÎSÇù0\ƒ‹´\?Œê´áò;ô¼RqœÃ5¸¨[ývGסµœm”MçÃp .Òr?ŒjÕ£YU4ñ"Ú4®þE\-š+Uý6.5MìçCqõ/Òr¹ê^,ÕMìçCqõ/Òríùáa«68Íòþ ‰ýã|(®þEY/Mõʕ;ãŠK W'T•šØ;·ãê]ÄçJ\ñ®óۋ_¾,{lÔMìçÃqõ.Ê;Š-qen¸:ù‡Ýxã¼ì‘ª›Ø;·ãê]4ˆ£*,WÚâæ)­Š«ó~(EO¢Må’/Ú÷#¢âÂùåªÇ¸äã|H.ÅÀn÷X®µW£‹ç¯AeNä’/ªúC%;s Ï\BsŠCqœÉ%_T÷$[DX®W;Ê.é"Ñ Í« ¸—|Q&°üÂeÎ=Üy䒎óa¹ä‹ +E2þW=/WÁá’.ªn»Ê·EÞÙ¹j—t‘è¶²¾Æ6ÓJ\‚Ã%_”ßö¿ž#W铫{œÍ%_T ö+Càª8\òE½H0?qÙL—Q\Ù8WÃá’/’gÆé>®Îq>ès¥”ºór=ŸÞa?bšK©;3×Cÿøšü²¡ÎæuÕ»ꝪHqPJÛ:k®|¾!çéw·§†u\y1Ô׏áŒF~™WsÛìø9QeäÚÉÔ—Pì(É/4¬®KüuòÈȵ™‚ TSë¼;Àz齺 ®u+ M?\™j« ºã “Òdúu\©l)^¸š÷§»nÝî«ko»õʺ ®Dºµ®êºQ(¾unڑÀ[v…².Ÿ«öÉUtv¬÷7ïÒqY·äsM]Õ2¿ú®òöNå“+ª›v^Ȭ©K㊯ۧoƒ8ñƕu—áòžÒߌ§©KãJ®£0qÙÄóҟá¦×VËIÚªº$®Õõq¼=™t®êöÓ5ä$mU]WÚ}tk;.CúáõÏÍÝ[ÙtĪ윑Ò×%qÏ]ÓÆ+W¢ûѧ“T<¶ÔçÊ/ƒô8„wÞ¸2]:ÎeO¹éÀd#©;x®ýåóŽŸ|ðÆuŽš¸1‘†‘¶.‰«¸ÈÐÑÒKo\—½Îûƒ:À:eR¼Ë¹¶.‰ nÙ¯qëë¢Z{þ⇬ã‹õu•\ÃÄÎEu¯G÷叫“Òkmñîm®¾X_—ÂU_ `ü`;®±}½n=é½ÄÕ0‹V[—ÂÕ\~<ºeK®±}ØByŽCš—ƺ.]_ˆ¾ç²Ú_ÚÌÒ|Õ¢¯Kàj/Žùô[\½,Ú¸ôdЍKá:;æ“[öÉÕyіL¡ú’9]] +×Ù1×'ï“ëý ì —J•l:ZÇuvÌõ©¾—1ïë9Sš\ùPÔuñ~ùäËãÿc—‹|¶—‡á¤¦ÒLrTu \ÕÉOnÙ?×­µ«^(u@Õ%póÉ-OÁõ. +‰vЌÕ%póÉ-[raß-Z‹ÁX]—x÷b멸n‰×f®^]×Ù1ŸEr”Ë&ûø*™ìе\cu)\o&˜4·õS/\²{ãb§®.…ëM2âúì-¹JÜú¡k¬.…ëØÓUt}Q7®D²­x”KW—Âçð±‰ËæÜM.ý9Õù±º®ê|²&±çڍO¿6ÝyÈJË5V—ÂUߜº7®ªÛŸûÞmz«Kájn³Q.›sˆçkãï·M­–k¬®!ž—Þ¶%ä]A ®qö¶ ©Ÿ,ŽÕ¥puÞ ë«™«õ¹F꒸r—Õ¹ìf¤jŸk¤.ƒ«´çZãÒmú¡ÿ VÑ×%qƒßxàjô +3àj¸ëQ2\ŸÊ(—Õû7䵘_ÚQ.}]—îý¬n¹:}l \Úº$®úêÓǹ¬²Þè!Ón”ØÔµ*–ïí¹Ê×ëMóU|–ïY +¶X¾ë“kz.ó떗ÉUüÓr•‹ä2/pÉe3aþ䚞Ëjb¹h®õ"¹Ä?-WºH.ólõA¹’ere0ðµü>ŽO®¸ö0ðÅ}Ïn‘\ðA¹ª Z~¯Ù\Åô²×å÷ÐÍULMÞá¾70¸@ªrÃ\ e’ºÒò{9ç*Š+[\Àa +%°ß{ZÀ‘›ì ù=Å¡­´e&=@~¯thG„â‚¥Âèo‘ßoXÀQã¸÷}ô•±mç˜Á8lc®Á9æ½Qæ#/Á9°Üè–ã‚s`™±Åš3‡}€²×ÀXcV@éK`3Ëڬހò9°ÊÜX@=€ÀXa6.@l`3°½9êT˜ËÍ"8á Kèmœ£ Jè„m®gƒú¡€S˜ „A:àª%ô¢©€ìڐ„>G˜ ‡bH}fv_ï\bAB/0Ò -Vè׋‘Ã]‡+_Ž V˜Ȑ+ A,0 +-V裥ÈaÜ媗#ˆ(Â-ôDˆ *âƒ-ôéBäpÝåB} Â(»‚-ôÇ¥€VÏP„#C̾:\ÕB")£œ· Å }ºÙHd.„Ð'‹TæB,Ýċu+_†pd8üƒ"âȇxà B8j¤—Â!Gl#´A `1Û¨«>BðÌØå +h)‚¸xí\Åú,(ÖCéÑg­¡% ÇÜ ýŽhIÂ1ó3?ú•‚+~€áï€d¼s°=z @KŽy>r’s˜y€Õø©bå™a÷H*:sˆH؇–(30Ê&ÐúyÖ9eˆιÈQDs‘ƒ²Ôā9£Ò7”AОQéI+Ò@½t>¥Ï)Mª’ζÚ&HšÔ¡9›!"li¥åڇkˆ´åhél¨vc! »ô™ ±¢g83âžö¼nų¢ †®@žâÌcˆñqCË`3Ĉ9qx@Ë`iˆf(Í4€ó`¦Ÿ¬Tԇ -g€M>kΩj-k€MœdY“½´¬6± +ÈcX]>±rz‹€5D'VFÔ +œéöÔ1GNÀY™8樼A:©ÔgB©œÇ Üϙ.H,8ޏÃtºc wàÊêd†kÍÁ…Tú‰:,c=càÔ4Æ €?R§é°ŒÖÛNÓaә_‚& :C¢Åqí±`»0ºk…äªé0‘qƒph­ ±÷UKó„ªY.´v†èuâ,øV­!zÕzìÓÝ ¹ð†èQ:j ›ÖÖãrfWŠØ ¬OKüñÍPË%¢¹-±±’.h­ ѓ&æV>¬­'BõÊXZ?Þ¹±´°öõ^†˜È,e \<1÷3–½í#×½{&ܸ¥rU¤s©ÍJÉ\"š LdöܹK0‘;¸)82‡i\o\´;¼•Ÿ'–‘P¬.t¬Â^¿¹1p1_uFÃÒÇàd}¡ãNSbé¥ +\EiW°/)áøf08Ô&[õ cœFwžÿf<[l2êR6W›qÀúßtŽ*OôÛø\‹+Š¿S;‹añcq€‰‹ÙaQt_zî¬ñ¹‘‘«ˆ¸ÿ¥ó/9k·6\"â—{”56¼OßYqYtØqœ=šÌñ…Ie˜>˜¹l:ìŒöªÿ짌ý¹K.ê4Li¯ƒ~/ÛÌæqµ¶\Mä¦ÜÝo·Û/¯oåe»}È,?mcÍå¢ÃœSþ#†KȵqÀe'‰³tŽ+¼Û9á +®ÃÌK_8.±´îBrvm¦(ˆ=$W›…ÄupÇU/«»Ð\¬•O_ºäj‚áÚ´.¹‚ÑzÜöžKdKÑxw gÑ q!Øý^ +—XŒÒ¸°DôÖ!‰kvKÄgиš…X!•kæø—°MäšÕ)¹/T®9½3eû‰Ê5c`OJš#sÍ6Ähi/t®™†1±ŒÁ5Ï#îí2¸fbÔ,%=pÍ`sM®ôT9×ÄÚÁÈdr‰<\)´ášRY©Ã\®éÀx™dl.FÚÏ$ŽËšk¢Éóā×þ9椰áòoŠü,M+.ß`ɧv\~UÑ&Yؒ˧ƒ¶Ê¶åòf—ŒoÍEΡö41qÏåcÚb™®î†Ë½,ڟ›pÂÕ +·¶øhß"7\o¶è®Ë’CW+Âé,—\ŽºìþІÆÕŠ'küâª-.¹ø©ÕªGw-qËe‘^Hݞ“‹Kæ–ʇìþ‹ë6øà"æÅÇ[ï¹ðÃõV^qÙññýw/·÷Æuê5ƒAÞm_}ÝÛ'ש۞¶wê~z|õy_ß\çŽ;žpØ>ÜËývûøúêý–“pÍPàÿÿÿârõä +äÿÿEޱ‚0„wžâ5±µ- tDƒ B}€ÆÅ 5mÑðöRcÂrÃÝ}—;ˆh{âÀˆRŽwsœP«ã¥j 1­ÿH«!WÏn蜷Ò렔Ã(ûµxÌt”š&)f€h<ëŸGM^"Ši(† Äv8 q!Ý´ÌWÖ¨ñêݯ˜ÄóeǼ&ÛÝî(ç{Ä!Èûê`:¨µÓö­U@ £/¯Þòpendstream +endobj +147 0 obj +6284 +endobj +148 0 obj<>>>endobj +149 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +150 0 obj +31 +endobj +151 0 obj<>>>/Annots 13 0 R>>endobj +152 0 obj<>stream +xڍUÉnÛ0½û+99@¤JòÞ[³Â@5vŠ|¡%ÊfB‘*IÙp¿¾3¢/IÑ€!R3ïͼ¡~ubˆðÃ(Þ²²s=ï|¸Ÿ@Á¼€~ÜG0õažwSà –ñËù3"úDŽ<$è%£0!Ô|-,X]¸-3X^ +%¬3Ìic¡dªf*£7"ç„rÜÄV T¡MéŸñ ܚÍ.K\>}þ$qÏgL)ˆP+˜í¬ã%,º7Oéìbq ?¸±$ãÐóž@<"Þx>‰ÂFW{ìۆ›àÛS}„zÜü”œç}UÅ ÒÆ±¥ä^ a$Û¡NCgÉ`ºâ¤_Ú&€ aê`Í,1¸›w¢0ÂÞÐ_L0 âd”„C(!Ž&È˯$̨q.{¸D²KÎä|Ã%¦Éa¹ƒ¿F=„aq8> +ûþøIöÎhœ1«=ñ–Û³;˜í-’×™kTNFíÉ.8M•-µC7uLåÌä‡ÂZ-ëW£0)}o6\åd8DSÜ !ðê˜Ú¢/B —ºF&k;ùƒÎÁ57/\òdØtܤPÃÒذõáÞM8 íCM §¸;Ø…:i‰ÞÍïƒiš¢E™‡/™Å¹! ˜Š­ßH„g½ldÀ¯š×˜Іgð™x¥í(Ý2N]t?§·WðxÇ£Éâò +fho|ÿ…[ËV®¥Î^6ûrMo)窚á&r®Zª˜™†XZ}–ÒÖyµn †c qQÔ*£f0)ÜîÝú°<·€eÙjóò:þK£·–$‹T[7ˌ¨ÜA·Í†h„]¤é-w€%ãGFÐÍ{¬æ_¸"I¼z0¯ÌU•ój•s?–ï3FõØõLÖ~¶³Ú:]Šß˜{Ó^/º€‡¯Oð°>P_t³Ú®œÜ'ª‹·¨A8ˆ—g|© /Á’ÚT¼E§)š„9@‹Ô gb¯Ji•¬-©}{Ýõ#œZ «³ºDbÿsáýû*G„6+¦šz`jݸ¹ÐRêm3ž¼1„ýè³dm–dLó¸O´H†#8¥Ñ!xsÞ2ï?A>X¯ïõ}¦úã(œ "܍Ûëï{ç=!Ãendstream +endobj +153 0 obj +844 +endobj +154 0 obj<>>>>>endobj +155 0 obj<>stream +xڝ‘;oƒ0€w~ōÉÅÆ%Îh¢Vê‰gëb“º£ú¡¨ÿ¾6 R—©ìåNß}ºÇW† ŒAU§/§¬áÙÓ«„€€i¡¦¤ ÀûÍ;®w°åŸ w`ƒ!‡&è±×æÂôðfœã˜Âùínøê+!GUTþ!«¢¬µÚxeáTPpF\Ô¤ŒHDVQj£ûv^MÿU=ÿê‰I9‡Eú‚EÅÙ­«öбcÃn½s—E tYõvóà¯Â*`ý¤vÞ +?[—& bLÅ9"4Þ&ßá2Uá”#d_¤«Æ¸µjR¥ì ÏNه肁endstream +endobj +156 0 obj +244 +endobj +157 0 obj<>>>>>endobj +158 0 obj<>stream +xڝUMÛ6½ûWÌqð*þŠw÷Ø ÚC².֛ô°ZÙìR¤JRrüïû†’?"-P0,™3ï͛7ÿGSšà3¥û͗”W£ëÑ»O4›ÐºÄ÷2›Óò~AëâfJw´òÚFm·ô|‘+zjÙ·š÷·ë¿¶ éTÂ»ùì>›Ièz§å;UGöT{×ê‚)K®'WÒÎí)î˜>ºªr–^¾üþçÞÞù·uh4½´ Ý-&ÙC‡Ã琕wÃՏÔpx¶ÌR=Ÿœ§+¨;²ìÜ‰ú˜¥þY–Ú©@µQۆ‹Äôuö~™Ñ‹5úé³Î½ ®Œò–¾i[¸}H¿ùYåOÏã®>>>>>endobj +161 0 obj<>stream +xڍWÑRÛ8}ç+î#!†Ð °¥´ Í6îì /Š,5¶äJ2Þôë÷\Évˆ 2%ޤ«{Ï9÷\óãhNgø7§÷ü#ë£ëüèôó4¿¤¼ÄÊÅåevAyqœoåJnŒ­ìÓî]þÛ4Ÿ§m³ó‹lÁÛ>~[®H{Z ¯ +jkHRµrOÚ<ѝ ÊÈa +á +’¢ª°3 ü¸¸tÚÞ¾t6Xi«²Žî–ËŒÿ£@|¥ '«çï³s¾ZÕk'$b­wT؟Êx²%5K9dQŒŸ½rÏøU ӖB†Ö)çOâŽNWb“o›Æº‚qnFý苖Îz[†ÉÍÿhSØ×5ʉ˜¸ßù ê¬ß7€ÃɪÔFy{š¾J*Qe3Ԏ";…lð‰Š_\¤ïvíê±MÐåVz«¨V…“½þ©NÈ)o«–·¦b½åÃ&£>"ï,17ä\8k KËK•eÎvL‰e¨ vruŸ£§Mk +§ +ÏçÂÆ¶)D†j]1ØeôÍÄ,bº—9ll§pWJFTȼg¥TÞOn•ÖǺ-BP)öu+#Ý®IϵØ2°:€º•ª­ýJB{.ܐ8€°UÁ ƒÅ׆ø+±S(•ø€m¸FÆèvyÌrRî„ñœþ¡Âoó|yBÝF#„áC`CG”:µîu‹Ç©ô_RQ¾ÁPĒä°È-=kÕ¡3d[‘ˆG’>·ž´êô5¯ìÕ56LëƯWk³[;\¨Ü“è òYQöÒÖM¥‚b*OçÙÙ(¸ëØ:ŒtØ» rBfL¾°µÐHØMÒ…œäA½ 2ºÑOʇ×Bå«Ò­@< ]‰u¥€•-»1 ±ãl9¹—«Í’;îMt¶8Ë®xõû¦u~ ½D3¤ÚÁ¡o×µìB΀•Þ5¥h}´cXÃaüãŒî£] k ‰¥N®&¨5úG kkë5›b.OÀ< “Ê8‚ð^?¶kËá²­„ƒ«yœMX>·¾1jèñ]ŸûHlߍxV£o!¬•Zp¡m=u0îM¶Bv7J~Ö'Žæ¶Ñª·p\i»·YøXáBå?ÃFAsVJ†žnýlklg8¥ òµè  $ðâ¶H ¸í0ªÜ¯¥v~:bö*ÚR›¸9Æy»ÖϺâl߬µ_OvÁšð©ãEÓTCs ­4x0‡0 ac‰2ú6fÛ@°5'H•åGý¸´endstream +endobj +162 0 obj +1361 +endobj +163 0 obj<>>>>>endobj +164 0 obj<>stream +xڅUÁrÓ0½ç+–\Hg7NCÒÞ `Ê4 —^TYŽEeÉH2nþž]IvS†É!±¼»o÷½·Ê¯IKüä°]ÁÙx=¹ÜMNß_@¾…]‰o6Ûm¶]1»¶R{aáÊÊߺ“ÝOŒ[CžÇ¸Åj“­ãŠRÃÛï×7ÀvÒy0%-è«6V@)•§0×.KÉÁ`ÐÄ"YL•š«¶_8V7Jôï© „ÎϲAGH(…¢SÂûÅ5ã÷Ìð™9a? Lp%Ü=ýNU\?*‰U}%]ê +ƒxÚxØ -,óØqãe͘Ö7­Af!ËRX¡‡Â8a!”›ƒô±^!jdÁ‡r•éà`ZàLCg%žà“Óé!½§zFŒm ¥Ž }%j|¼YYæQÀÅz™SÜWá;cï¥ÞÿO»ˆÈs›6‰  ÇáÝÁy„c¨k½©™—x¬à*<+ “¾ƒñ6…ù:Âg°C–G#`Ó¹@Žá„o›`’„†g’'Þ=¶.©Ö÷åŽPqR•q1 +Gû‘P7jÝH=†ÆÑÃ#Î(©}œ.8–óÖ¢¼<˜÷çcýtsÊ£yÙ£ Hà;¤‹s|RÏI‚#|éÑl¬Æ(…P¡°XHð¾˜xÀr‘fêØQeΉ T®nqH'”à>ô‰w‡´b‡çè]%yÕӅ«·3‘í3˜¦ü×D^>%2Ÿ­¦ÙíI*×»(ì,SŽT3¿%-ntÜ&9n&q‰%Ç­H{jÈÙbGä2nÍ"qoˆöæÈ¡§ØLoÒç„d£!Évð7£Õ­ò’.•H€ƒÆ ²D!Cɦ:8²z¯tßÉ<8J<„{iÎñG؄‡Ãè—¬P¤@t 9A 6§B¡*žfp)8ìØ$Ø4éà­8þ|¸IÂH#ôgÒæ‰3‘òX߀ÝᇽMSs ¢¾dRµVL¡Õ +L\Bڛãb#ðsî?¼Ý^D±Ï“Øùú¯§³eú— Þ¹1¥ïHü7E-µ ¦Á_˜nYXÝEL[lWËü7­Ï—Ù„·¯èùÝnòmòH·P|endstream +endobj +165 0 obj +820 +endobj +166 0 obj<>>>>>endobj +167 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS04±Ð³P072PIÑp VÎO+)O,JUpLÉÍÌË,.)J,É/*VðMÌ+MÌÑ Éâ҅h҅ê2‰™šé™+€ùE™y%©E +.E™e©EÅ Y×®@.º^%—endstream +endobj +168 0 obj +126 +endobj +169 0 obj<>>>/Annots 19 0 R>>endobj +170 0 obj<>stream +xڕUÛrÛ6}×Wì[Ó‰âEÖ%o±c¹ê$ŽjÑÓËô"A + 0þ¾»-Ój¦£F öröìÙå—Q1~X¤Í¡£ë|4]¯ !¯ Y,¢+˜/f—oR˜Àu'šR¨˜*a£¬cMCכÇíîÇü/tA’ë$øN²t¥äž„…âÀZÇ Øƒ>ZÀœ†=õEˆîÀáFK©<Þo~ƒ­ÊQžÝÉ:.#ØTpÒ0ß|<(‚p›â(ƪèHèx¸ƒ,Í¢dYÍAb¥KÄn ì¨æ¯^è^(fNP +ëŒØwN ŠÊhPa¡pä{°Âñ1´Fœ—Týkyá͝p /Çð:žij¸Š–<ÿb?°0‹—Hí·ì‡h?O¢ÅE½/]L}¦¨gaÐ\ׁ’÷J¨´ç qäMT°Béx„¨“YŒð/£îtg +þ¨Þ{FÞ1L®âȋïé„á’+g_ + Òy0ú]w? zu„)xw¿ÛÀ Z¶¢Aѝ¥æ›ˆmB ¡{I½³ œÅ$jJ¶àv,Q·%·¢V¾Ñ¾p”wdm:E¡¨û^ªºå†y­†ÀcR9ÿJéŸäƒZæ¦bXz#ö†ˆ%íKmèʛU¢AëŸïYñ™«Ò^äµ]KK8 +wqq¨:¤Æj X*1íGQmuåþL¯æð«P%ŽýŽúˆOì­uÀ($«=„—8¶ˆoWÑ:xØlÇDޙlrûy{{7†í=ùf½{§?>l®û*‘Ïè¼'…F }¡Rtç(œÅáBI„ê /»ÓTòóÅáNÜ2{BUîH{`k4Za%C‚ñ‹°A +c°¬@ëEâ¢3娋Amoeù3``îí7f8ÂK’ ²%¤É +ç&Ü^±é:†i6#Ó4ŒDåÚ·Ó)žÇzì1B½NÛn?=£xeÔ.ö-Æ<·²_’}æ´rU¥ô+Jâ`´Œ xwÿµÑUÈS- (z0iiQ„è Å¥"ÙW&¶'Ùà¶üÞf´ÿ$$K"Ì_¾‹µÙ*äz&­V]¤MíóÀþ?[9ÒRꢣåÂüþƉ¯´‘Ì9䦳4ÍÄÝOùÇï?݀í5w~©þð‚pú£@¶kîžÔ7]/[«À÷¼WgË×hL拞Ø_F)è@endstream +endobj +171 0 obj +905 +endobj +172 0 obj<>>>/Annots 22 0 R>>endobj +173 0 obj<>stream +xڍVÛnÚ@}ç+F•Ú)¾B!RrƒRQšW•ª¾,ö:lk¯ÝÝ5ÄßÙµ Ɓ9ÁޙsÎ\ŽùÛñÀÅ®ú7H:w~Ç÷ÁóÀðÉ`Ø·‡à‡ÝOþ—ÙÃ×{i¤6DPˆDšÜ\ø¿;~ǵ]L£/ž¾,&˜ÌÆàë'àzö úóÆhEˆpÆ.Œ4(ò Üu¥Tvã8›ÍƦDrciâ¬T‡i ÁwyÜ*OWßvÆ#ðú:›…鬫+ÄÇt÷i’±˜ñ¸ÿþô\Üiµz»oŽáCÈ%•0™’«4Hy*ý—½ä(_­($äXŒç±2¹( ±8©€?rV4±ÁoÆÖàé]Ù= Ù +Udô¦$¸+‹Õ3ôނíì’=ÎýÇž£¹ã#ѐF$0.‰c¢XÊaÃâ²\)Fò¶·Œ››5~™µëäRìuðö±5ùïXÈ T*Ö +¡J/a³bÁªUÃ-]S±LQD)€¾2©të2Á¸ùG!AüvFSìJéam„§x_´0ã4( ƒ?$ß²2í~mkK3u^³êu-Ÿlà42lžæ“KøüôˆW:_šÒÿœMï fKALiµ>ÔV«§¡Q[ÏT=[¡¿º8f 9ÄžÖFU Qƃ8é9Í7ºØ²uôׅîÐ{l§È +7IRu¨È÷ãÙíäù  ÙÃÁ“”¯™HyB¹œCF–¸ž­Fãá¶!‘s^R՟ãMDº˜Jzðƚ:2M¨SÏuñ¦Æ¨ŒkQñĐÙÉæ¤Ø¶}r2¾rô¬+¬ÈšîT`}W(K^Âï\ªV¢=ì$Öj™³84«7ÉÞ7Zwg³ÓrütiuÀspÔo[ûº]Õ3˜×q Qµú,>ûuÝ-Ó9ý< ð¡hxhHh‚«µ,4{D<Î߬Š\2îy&Cx×ña+¢_MH£®î'¢€tEÁ–¹^裂~Pc A..F\ ×QÕ»–eº°‘Nj÷ðoúm–…/ µÚ…轨w6&Á2%«©¸®H4§èÇíb>OnŽÒlè3œZoãñÿ¿j×GŸÔ=¡¯E3Ô- Y±-O{£am*чºçõ°¶ƒQóÍ_Ï܆ 㺠÷UÂÂsëxËë1ÌúÐsuÔPßë»}ûÜÃ_3ð;Ò·Î?;,Éãendstream +endobj +174 0 obj +930 +endobj +175 0 obj<>>>>>endobj +176 0 obj<>stream +xÚmRKSÛ0¾ûWìp‚¬ØÆ 7 á֖÷ÆE±dG`kdòïÑ*q†PÆKûí÷ØÕ[’C¾® ¸šC3$wu2{(!Ï¡néj^•¬‚Zœßÿ{\ÅÖm¹‘Àµ-¥‡Ð!¬yóJ¿;ô°0¥Ò؝ur¸¤ +lUß»Œð]‚ÛH ê‹ú%É Í¯XAjG¡­r› ¾+zmcÔè¢#•¶ŽÖ=âDZƒÃÁÑ( ÿ\ºÿi)¦!aZÌYIš5ÂgºÓÀÿù_Kè±ëÂAià ¢ƒçs$Ã5œYʆ頩Ñw›ç tɾä% ,ÞJs Æëxuðü£žÂÓTnˆböÁâ°ª´ˆ1جñ£eS”åïzù´‡Nk=I}Û:iB€WòM)9´r ;igáÍKKÂö›‘Äq¬Ã$h'„³ÍF +ßÞ ÆIñ5µw8„`Mhß±½Éê`2/«ððò9›Ÿßj’¾ƒÒʺ°U4~qíyºoK¯‹,vá0ªž’Mo¬¬2¶€X\ÐyY'“Åz÷[endstream +endobj +177 0 obj +423 +endobj +178 0 obj<>>>>>endobj +179 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS04±Ð³P072PIÑp VÎO+)O,JUpLÉÍÌË,.)J,É/*VðMÌ+MÌÑ Éâ҅h҅ê24 š˜è™*@ŒÉÏ-ÈÌÉÌKW’t á +ä®$×endstream +endobj +180 0 obj +124 +endobj +181 0 obj<>>>>>endobj +182 0 obj<>stream +xڍUQoÚ0~çWœ*Mc”½m“6­S[èÞMì€ÛÄvmĿߝ¬%´jÅCE}wßwß}w<õRã'…y“äUïûº7ú±€l ëÒÅfó)¬y ÜX©¼°p[‹ZÀ5Sl+*¡ü—õ&M!M))¡¬d’͇%®wÒA¾c†2¹tyíœp°Óðç¨4—ÅqLqà¢^€!(x" ZÁQ×ÜÑyQ #ÜÒ9Á!™Ž‡—J@i¯¤‚+]UXï”Æf³á´ãæ±ß¤ž¦ô!•€•¥>8bB谅¶rw>²ÅöB¾tÞ2/‘´gîÑAauášBI)•M tUZI•”êÉJ‡ÚÁ*#©¶D-Ô¤§ðRçÌ ¨‹?ï{T;;*妋å¹×öØá*b0º@ +•¶±3ìW+Ô_>¾°9oDÛW#ÝyèÛ3ÿÆ9õMº6¢oQÝÛÓÎCúíäp¢W÷7«0]'+SÁÖ¯ªõŽKÒïBÚEb.@2Â׶Ăbqϒ,°ø­ô£Ö¶‰‰±YŒí7üN +ô!YB²? äb/sэ»éT3¼±ü³^Þuö7l„Z–ãn„?õˆ=®i°<ö¼g%ÞfÛ7V¶ö>ß¶Y«ØIgÏ:*V¡Ÿ˜BH¨ Í%Íæ ˜ '·ÒãßÝÑì„rñfԊãcŽNtC¸WÁ‚©Úî^¸AÇÊÔOk€L—ƒ|€KÓá«´?›9s"qHCz¹À$ÿ ûÏ>øËt[ޅú¼ë¦ßXÂþg¥ÿŸ®ñ³y[Ò%å<œå|@ó—&ye·5qpF䲐8oÒ%ÃýÝOZÔB–"(„W^È6Â)4G:f9rCGkW£ms†l˜“9Ð-ÁÃï%¿Y—ËçΧM‰÷~„¦ó)^…1…¦)ýc¹îÝöþi£ +Ïendstream +endobj +183 0 obj +729 +endobj +184 0 obj<>>>>>endobj +185 0 obj<>stream +xÚµWmoâFþίEª”S‹B@ªÚ¤—¨­.=8õC’‹wöbïúöB}g×v°BóVEa=;ÏÌ3ÏÌ8ß:ôð'‚ÁÈ}â¬s¶è„#ˆ"X$îht2 N`Až²iHÙ:t ’±‹¯t£AÐwž…ݟ³9TISÖäր‘`V tÎbžpFÁù +U ݺ‡•1ù4 ¯¬fÊaMs¢õF*úËÍJj㎮¦¹Tæ&TLK«âv¨<ƒ×æóûl¹âÂ0R‚®™ +`FÍ,fér¢0¼«²„ØÔh1D‡8JsŠVلß,³oÊáÓìãCÞÙ!prš²tún’¨<‚cyXóø`È1'-ü«Ÿen¸úæ-‘žqì«d Õ.fL,±™xωLS¹áâ¶%QÍ\Η[o˜§VÃõñ÷× ^á£K1-üÇ¥ÿþ[µÛCçáz0ì•aõª–Äҟг~uæPÚqvaΜÎ×]gƒ¡*Ò ¿Â®…¾˜Ý»n89-l¶t=“%†€óñ2T¤›m—­™xÕ=‚â²Ìâ;,Ì{@JJŸ@Ä'ÿ bOQV ݆C~“v/u%élùãr7`ê~òþ¾»UÒæï8¡æ—gØsAåFc“4¦Xí2u7槗g§ eb6D"2¾c¦6FË¥ð¦AVFµ‹ç4ÏçŸI#c™¾|5´ˆ¯ï‰IÔëù$»ãþ®¢ûòG%êÖfL˜‡ø‹¶œ!óXñÜÀ¬Lç#Óþgž_ßë^Ž ®«¼¸ô³¯˜ŽX/mãU+z¢!c”Ðüö0XÎ GV…4~|® OÉax[iAfܔ8çr9Z[’æ„füQçÇ2ˈ ¥& ˦ ‚‘‹ç‹/ÕÜ Qt—²â¸Æ[¾·âgFàtƒÒõ •ôéõf¸€³(/4õ!$$FiyÞ5¤2öۂ —{¸þ’fµ +5îÆ6×a&)KÛQ®Xl¤Ú"ëfå¹<êfGeÙ¦•óI%ÿ¾Oø;ðÎS¾ ËD¡›WciRh¬à®áçÒ9t×MÃbÅ´í²¦Q-ö›ó?矛ùøž> ü½>>>>>endobj +188 0 obj<>stream +xÚ­VMoÛ8½ûW ,ê‘l9†î-mÓCi⢗^(‘ŠP¤JRqüï;CRŽìÄØd[Ø[šÏ÷Þ ùkTÀ?,gp¶€ª½_&ŸÞA±„UoËe¾€_Y©½°ðA1ç„{»ºC»9E´Ëf‹|Nv¾_ÝSÊllMÞÀ­5] N6R1 m ä@j`ã,Rœqz eÙÏ1ÎáÇZOçРÍþ pgJÊÄ¢ã)øµ gk+ÎòÕ¶‘JA)ÐÇT»àPnƒi-­óÀîVX*Ñ×H%ú5ó1jž¢õ®0ç} hýX@ènÕl§CŽØÍ´ïFµŒ7Rô•i¦9l¤_·“¬=zr’U'`Z/vÿöÁޑ—ÍBIÿÀ¤sv¢d9Iñ!k£í,ÚöïCVí[ ðßÙ\~]]^ïכ…Ô=»&wt>G#H•Ì#ü¬ó¦a^V(˜-Ȥn„Óo<ˆé|ˆ²¹;lï:ä +5àyèQy (¯j·‡Ðî|šŸSØá½Ô·¡Š¢fòp5÷™áÀfœðÁ…'—^<&‰þ¯É†ÿ\ø>.\8ì‘Q”?Ó`å3{Û5çµAÕkÖ0uø}P¾ÏÉtÀˆg6PBHÜxÓ¶ô'qr|c­ž¢,4­'UbØC.Ýs–‰$“J +ŽëÙõò«À5e…kEåå½PÛÿ ©”z˂— ôŽZ ŸA¤T÷ëB¡º8®JfQÛ1:‡†m±qÚº¬ªDö´ƒÚ¤Sé9…²ó°14ñ¬ò]Xq§3½ÅŬ„ƒM‰aKá–:bH Ž»búÁ/.‡ºS´O†j˜ª;]…(¡%­–é%Ê ·we¬E:’—Áš.°ŒÈW¨þ ;µà6«Ã)0H‰µDÎ8ü§2¾=®à‹€R/ákqGâè5 ŸSú—ª8bþې計wä-ÝHf?²¼oüUʦ”Rü¡²)Rªðoû6ØϟÓÁI_1M÷šé–nO YZl¡€öܘr†|íŽ\´?ÕÞÍ'€ŽÅZjéւ¦Ì„³gmÍðX,^Š‚@ŸN‘³¡KI½¡s³6 Fj¦+\»zOÂñTÁ F(bB9¼)áÔÐu,ꀁ2Ø搆‡ýƒ•Ô~ž.æçÈÙ¢˜î.‹7¦öš£ :ƒðзÌŒø…i\äE§l9›¹ŠÎ—s4o‹3zp¹}ýÙITendstream +endobj +189 0 obj +973 +endobj +190 0 obj<>>>>>endobj +191 0 obj<>stream +xÚ-‹A‚0D÷ÿ³ÔÈÇF»U¢; ß4R’(±­ñúZ53«÷òĨ>clwù÷™ŽB›³3d+]jìë +Ò¯š[Û¡[†ô2ÁâÐÏλ˜‚IKˆ¸ÿ4ÓZF*~Qñ¯Xe¨¸.¾  Î'ÐL&F³= ]é Úl%®endstream +endobj +192 0 obj +126 +endobj +193 0 obj<>>>>>endobj +194 0 obj<>stream +xڝTێÚ0}ç+F+­JUåJÊ¥oí +Ô>tKKöLâwÛµ(¿c'aÙ°´U…„L2gæœã3üEâ'‚Y “)dõèS: +V ˆCH ˆf˜ÎHóq¬ã†ñlŽÚоNv´¦Ü¼M",(²0Ïâ¼I<óc MK¦!+‰4T.ÅA~ÁQ4™àÛ5Š‚))Ü=¬7 ©ÚSå·]HÃv ÁKBn;ޕ„ï,‡èðÄ0ÁaÅ*ª_ÒA`<õŠU¢p°vÆiz‹.,r©DF ́qWÝv »Žã`OT5RÿrÜr¦hf„:úðgÔ)-ɞBMr +Ė#§hÒړY1(^qó]9§8)ª Qfh lxâ¹õ€~~Xƒf;NPŸ‚F÷æèFʊa/)&Í`ôÍ@–Uäër çæC_¶°¿1'^ìܼ?è '¢Ëûtùc‡èn ER[Ɖ:¢MÚ(¶mœóŒ#¾ªtËڑ½â=ãÌøùUÏáÀLépœÔàJh×EÍew*;·xh'íñ¥PÞÉlÙ/Šv‹r=È)­¥P֌?çö^¨Ý9¶Á¶Qfx4§.m~Ñ·×òjê¡x¾6nor¨Ø£Ë`ŸF»³ÏžÚšª(ï3Jsfþ¾$î”û¯í‹eíwÍ{Å—&Œy¦(1}œ9=œ©}æG8&œšS‘R ¼\aTÕLk ™¾äú›uâöõ8(„¶çÆuÀñsÊ­Ý]Þ¢wµÈ¼S‡ßæ?z«ùùÆ$óûßMf mqôÞ>X¦£ï£'ß?¾bendstream +endobj +195 0 obj +622 +endobj +196 0 obj<>>>>>endobj +197 0 obj<>stream +xڕVQoÛ6~÷¯¸=ÕbÙ²ÇÍ[ÓµX­ËPía@^h‘йJ¤FRVýïwGR¶¬Z‚$@lÝñî¾ï»úo’ÂRXmè7¯&Ùdþy i +YO6Ûu²…ŒO³½Pï™zàöJ©äZ9&•T/þ»›ì_L^Ääi&ªúWi·ݑSà҈ÜɃ©®¥åMmy‚GÃL§}|8@›#~bŽºyw»€YºJ–Ônns‚?tg¿§pÂÙrí§ ­ÅÒËðx:/´žï˜™»ª¾Hœ^v2ómÔg©XYoÁë˜q¾E+ÌA`tã*Þ [Hc>G´]à—Ò°µ& uÞCzàŸ­þ¯ÂµÚ|‡‹|i £ôË®çž2BI¬)qtÎ|üûé[×d)­ÊB¡ «Ð~6º T¬-¶X°\àT +j³nVéøç©Ÿß1řáðåéÉG>ß$ðW¨ëb+E£b%fHO•DˆãR笼h¥•nïûfumtm$r;¨Ûà4ŠU¢8ÔÌZl™'1¨ÃåKáÕ±ÚwáKQU`9Îdé3>5`Hå#ýô¡+Á¥»&×ùCšÒóqõ²g‚ב²Õ*ÙPkOÒ«|Êþßß,[‹\™b(?+ñLÔÓDì™Ð…•㯲ÏSdúù†0œ©ö¬´Õäš:„uQ“Îý-ËNçmxF o!©/IF}ŸºhÅîü`Pºe9êï¾ü[`½–1lŽÌqnHA^{8ß-ˆøˆwÆØI•Òã^îô*³  C˔gyÔíŲhUÃòzŸöËT±|O†ù#ÔǬ1 éò>YàOúw|Äþ¤ÂpÆ;cy‹J¯oçi²án²ü¼s¤¹mvøï-އël aÇ5ÕX¦Œ”výÝg‡9¿ŒjìÑè֊·®ïXV_kt»]¢ýíe¾‹ƒwE¥•ÄÛ]‰ö؈J;艴̴ÈǓõK‹oÎÁÐÃí¾…½n­Y'“xß Ö¡àqÙîb¿})|ý3ûô0 +Â?xfÕø»ïªŽ#¯}Kî~`e#ÈOÈ¿¢ægöô6pRCÃõÒ½dîC øíä]MóŠÑŒç ÇïD½¯¥÷*½"²HÖç MÍñ¢ZžöÞz–uýë~ç{;UAþÍ/ïî’Þß°ý µV"¼ÔÕ©%©PmU¸¹þéÀh¿‹6¾¦ë-¾Àl¶ñ5ƛü7]¸–îüÞ 6þ`ªa%åÏBÚì~¹ ¬tC_®î·XmñêÛЧlò×äéÃTúendstream +endobj +198 0 obj +1018 +endobj +199 0 obj<>>>>>endobj +200 0 obj<>stream +xÚ­VMoÛ8½ûWÌ1]X²¥xm§( +¤Ý °m½ô EQ5[‰TI*®ÿý?äVŒÀh_¢!gÞ ß¼™ï“ æø—Á*‡Ë%Ðvòª˜ÌÞþ YEm?-׋t Euñácñæù³â+šÁ<‡$_¦ k½©a/{ ŠA¯¹øï6ÉÝgÈæi>"*  ûR0fK p BÈSȖS +ÖPr£§Ð). SP*¹sŽî/ìu. &ÔØø5»Ls•4=H*J´Å(ë —âþì8šlˆTßR(¶±S²lX ¤ëQŒ„’AÍ0ç? ÎÒyêÓ¼‚leÓL° Ébî˰ øní7û“y}·¹µ!xÅ4Ül\*Ù.AZ%јPÊ´*…Q²q‡^Í)Þl™0œ›ÔX£ñ§Ÿ(!ôåeº´¡ÿ•þÄIlŖ7΃ñĝ ¨8–Õð«¹ÀT"ÄèŽQ^#ìwE± —¤ÚÛÊc‰eÓȝ}ÌN³¾’Ñ+§¹uŽ +E« Ü#[¸Jj¦˜ +¤^¾F‡¬îóå*NkFª–?J*ñ„ÀŸõ÷鯳²í‘EH Åj¦˜ 9RÉ)3®*ÛßK§cP¿dvmˆÖLÿ¦ð®àòL _eùGPX?g†Àÿd<„dL‰kT‰®Ä$3äîR²u¡b€½V3½Åƒ3ÚwzVIz¼1,ǝ«¹t¯”ì‘L‡5Úá°ÆVÔTñÒ¶ÃÎò]†ýIúƄN‰z ÔüK¯>>>>>endobj +203 0 obj<>stream +xÚՖÍr›0Çï~Š=¶™XF_Î-MšNfÚNš¸ ‚<¡1à"’Lß¾+ bí©ƒñŒ¥¿V?­Ö»ûkFÁÇõ'ÉgV³ÅKX­õHG„Á*}w¹Ù”¯°®ÊHZæ"+HRæïW?gÌ©GâŽè±Tµ“°( +r6>í(™ Ã×Y¸Èó)ڜì½z¡v'¥ÚŸst蜅Ä3bçýfþ¤Y%“:{‘ +D%!yÎóçÐç JÀu¶ÝH8´{ÒV" +ø!áYÉê„áI"•‚uY½ÙmÏÉíë;T€ó…¬_ËêIX=m¾h¹Ûº(k„. P[™dëL®n¯ïµ¥\¨§ »"hVPÆÑ1‘uŒ5GcŸèàāfý¸šyÄÐ}ûºÿ~L"xLB aˆWÄ<äG÷=ôˆ HШcjûí)ª­2ßBy†ÉX7LhN?'˜hŒ«™Œº‡É’x¾½Ú!¡,vañ—1®we±ê!?6>a]’%s"‰؝ĨIBnÿ’„M32ÂD¨uæ0êAŸc<á®q‡‚“Ox4!z­z…q³4ìi€NàÐhBàZõ Ž×dæà¤q ¾Œ&D¯Uñ˜ëÝ9ÁÁ÷PMb«îò€ó&íõdÖñ´ŽY[Õ ¶[)*È +•¥³lÇÄç21™xÐ +±3K ¾žÁìϛP¾–ÅïÃeÞ®zõÐë÷a÷+®+…ȱ¦ÝށHÓ +ëÐù^úQԐ)[¨°f5¥ +KWû*Y½Èê¢Ý¾mUæÌo±mmF÷u +÷nîkYÈÁɳáÆe'rь7A;]_çr8ë¦pW7@ƒºãþgLêÚþŒFË´îç„)׿Çܖê´@ÿGó± éڈZŸØzàï:6!]ñp¶þ‡¦‡³)IšõçèÅMÜލÑáêûÝ<”ëúUÇêešgE¦êJÔe¥à‹(ž…É>s»hÞ¬¢¦AðCJ¸=I¼xˆo³?r gendstream +endobj +204 0 obj +764 +endobj +205 0 obj<>>>>>endobj +206 0 obj<>stream +xÚ½W]oÚ0}çW\í‰J%MòѽÑn­*mÕ6¨´^ÜÄ@¦`ÓØ)âßïÚ Ð¤ „µ«ˆØ÷Þs||®1O=l|9p}ˆ–½«IïâfŽ“xŽ€ºV“¸OÎ&zŽï㓭ŸKbÙú¥Ç¿Nzø ‹í>~ÝÂ0ÔùA€E±-ƒqC0q<Ë+£ !•hdUpñ]Ëר–eÕØ”#xxævæa¢[y ]k¨Qà ây4qÌïÌÅD·r!.éýðȔ„ŽÐq,љŽ‰n¥c»{ØBÆ:LÇ» ,»3"ºŽ’½.9@ßG(þ &.¢(Ùà¹A±[“yqc—ÝÖÿÂø¦Ú6`â$c‘Jž,s©€®VŒfp™Ä h½Â7Q•ÞZÅ*f.ÁênÙQ£\-&›«¦bñ «7nÎyI:f³„3 +“F‚˜Å,ÆURP%`Ų™È–Ÿ‹:QY‡„¨Ô~Jü Ž/ø+ì܋:„\ˆ<á‘m‘X Ó>r£yª¬éY×ì”-ÕzEe½F5Ã]€s™ð¹äáþî7¬¨”k‘Å@y óLä+˜%)“f§U þi >À7×).âTã4$59g½  +RöÌRí.{A£ˆI ‰Ä¶{ʱ`|²±F\ðÍRäòÃÝõ YötÏ4M´wXÆé’³ìœób¥ÖI`ãTlù¸s3£½¼ 5v{d©Ð&fî“ÜÈOEÿ´ï^ŸöÕ F”k£åóJ42¾Õ©­Ö97ð뚃 +x“Uß]Œù¥ÂGG£…6MkÖÍb¸ÝcÐáà%î}÷ÇEËbŽÇUɔÜë¬EÇÍìÊN»]íl³ŠwaõŸEmíŠÃä»4Ó^P/žH•§^¡/ŠãÍxEºC½[GÒ· îT©õ¶!ÊãSVΐ´Ô!,K8xA ñF^Þ«®~Œa,fjMñÖ5ړ™„ï”ç45R¤ b×o?Ã`¸ÿ‹S^ öþIŸ…>endstream +endobj +207 0 obj +787 +endobj +208 0 obj<>>>>>endobj +209 0 obj<>stream +xڝWßSÛ8~ç¯ØæåÒ66± !½¹¹JaÊL)\É=ÜL^[Žuµ%Ÿ$“æ¿¿])?cJRÈlk÷ûöÛÕjýßICüàlLŸ¤<ù8=9½ùÑL3|2¾¸Ç0Mû7¢àp£tɬy;ý Šü¢ ‡#Ztõ÷Ã#TZ=‰”`pw{w̙á)ddoW• `Ò][®éªäIΤ0%X‰’O\[·ÜÐ †þ„´lŽæ™ƒ§?Äq£³0&\Βܯã:„iÎÁS®)öKQòÑy‹{ßqéZLDž-ö¬Rž ‰Á Ì&*ވ içȒi¼ùÄDá¨+Ù¢LÖfe,/C‚šÖržyÍ_bÝPü¨X=q㘗j)wüM×$bA‘©lœ±L[Kasw“Rº‹¸d+˜óVh™* +µÄœÏW7ºÓP*ÝKóD-¤°BIÐuAèXZÀ°²*øÀµ¢²ü‡=ÍmYtåÄ{›Ô¤ÀÌïû´ k;ˆ`[?°ù‚ÙlÀ0œÐØþlkoÖ¢a<š½…÷0ëK¥K7{|žÞ}ù³‡š7ß|º¿šþóp÷go÷)ŽL#™ÐƂ]*¯՗\ùðœúL¢@–KCªaŠz!EÐ#yÝ¿=€ÑqV~#Ø\èÔ;n¥ aL'WfÇ¢ܙš%®¨©žw[‘dtЮ/‚.ðl³6Äi1Æ´Á’E¸¶ø™H)gUðbµ—¬Ü¯Þ9§CՑ’‡ŸÚð¬.0X.ÝJ¥ÅBHtG&ä¢EMÜn@Žeí‰:×bÓ§(p®éQª¸‘¿¡6ŒôÍÙ†µõLm©ôwG¹ °ìû³,%¤» iTÊ1…°+'>«­ÂŽ(V”ÂE­‘ªm«9ù\WÊŒ½ ë³Ö”JHlF,íÒ~ׯ,7֕Âz{%뚎'Èvk3‹Çíý;ëcõVÚ»¡< C‰D †˜¹>Pa®ÎZÕtfìÃ5ôéÂzÿâ‹ZJpùõÓQ®mWHo™ Ô¡b o8¾ÿv”ß7/Süz?=Ê@’Ïú½ŠYܨ²×­°{n-6å½R?iÛ~è½ ·Ë{G¡0“1ë«,3ܐæÂæ]1MuU›á)c¹oOO¬i£I]>^ÝÞb·¾ú6€¯_0½ü8€8‹ƒ(oœÈ«qü·«I0ÖuVÓÁ|]à1´¥â¹ ƒø|Ô&ì-îâ½9–Ö¤{þºwmä¤ë/Ô¹¼åQ¢Q˜[hÌOÍ_Ã¥½E= +ËäJÛÃÁ¢±K  lÜMX̋äÖ5j:]çbp™ +&{Žâ³)r}|fúpºX¿H:é½"f¡Ð1–ú!å’Ôš8xßhŽi”Ëfº üI±7ávŒÚL¸/èÛ1ÅÆ ‡í‰^Mš• ݏÁXۍy¼1 #Jî¤|i 4ªÖ ‹C„i…£Ê«5Z¶.Ý4ZLH`UU`2ÉÁ)žóÖ$ZT·nÖ²ª2-Û¦Á“Lä®Lаì|®™!!Ðke¬òW-¿¢d ~ú^ó>ÜÒj?u±£°6ß±8½™¬SE1ºOFËG•Ù%%í2-¾0ZÍÐØÀ“µoA4šÐ¦»ˆ‡déæ(>?À°ë%özzò×Éÿ¥Ã|âendstream +endobj +210 0 obj +1277 +endobj +211 0 obj<>>>>>endobj +212 0 obj<>stream +xڍUKSÛ0¾çWìä˜Ø‰CHh{¢f80Óé©ô Øk#*KB’ø÷]Ivš˜”arÉHûø»òó ƒ)ý2XÎàly=øºLnæe°*éfq1O/`UŒV'«'º\´—#«“c<ì2FPrp înï®Á½jƒÒŽ+Ʉx…ÆrYÑ햋"g¦€RpTÞ6MâãNl³ŽÿF˜V©o3…$;KgÎÐዛhÁ¸ŽaÈkVáäÔÿ=heÍ ×nøpÒ%Îéü?< +´ŽKæ~„ Xr‰t,ì˜3írj^cêãìÛb?''øÇqÄÆŒAAx7>x' 5ph¼ºŠ” „ 4ª&‚l:MÁ÷ 9Ä©±D‚.òG¥,ö^£Û"킂—%”,: ªl;YØ>RH®ä‹®’pCˆð…ÕZ÷¾E ‰hz‚Eïž4V}ÖN†îÁcZ žŠ“,Ò¼Ñ61̪^•1¼ª†4$ 1>fY@à”~ã“E?V[§ŽöÙiâÝ`=5rLDáI=rb ­gÇ¡¼×!6€Ã’çÓL–6ª2¬~¸þ ´ñÞ@ÓÈ/qI5æœwwÃd9“°ÆÝ<Õ솹ñ³ÐÂ/àsÃ7LÐDʼnìŠÕ ±ayŽÚÅfŽODÄLÕԔeƒ3(7Ü(é`à gkAµi›i÷×Xô:·Ûúíç÷{¸•T­d9ÂZ^I¸Ry(ü¹³ã“—†^ÄdÄì>©µ§IÖq'°}Õ,üòL%«ñ÷¡¶I¨Ðr[FñHîb¼çýΞ®È›)lYïí¿ ¶ +âîvŸ&‹j›-og½•.HÂýö]ÙךKݐ/—B´¹äªjÆ"•òRâu_´À³ù}:fçËØ#¯J·eᲨ¹äÖÑ+¥hgî˜l˜ðùILK–³©ÏºñDé5©™ Û9_úïQ¸šeþàz5ø1ø ¾b\endstream +endobj +213 0 obj +743 +endobj +214 0 obj<>>>>>endobj +215 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS04±Ð³P072PIÑp VÎO+)O,JUpLÉÍÌË,.)J,É/*VðMÌ+MÌÑ Éâ҅h҅ê22 š™êY*€Ü2sRÜò‹rKŠAR®!\\c$`endstream +endobj +216 0 obj +124 +endobj +217 0 obj<>>>>>endobj +218 0 obj<>stream +xڍU]oÚ0}çW\ñÔiÊ' Þ¶ª¨•:-S3MÓ:MÆ1ÄkbSÛ)ʿ߽”R:"A¾î¹>çžc Äx$0Ma4Þ >ƒhžAC±„t: +˜LÇP”g €ÜH儁œëV9©VïŠ?X0†$¡‚ ¯Fé4L©¨¨¤^±5U•Âr#‚«\|Ëo¡Ö+XÊZذÊ ™P Á8Ï â{%Œ§a.Ué+o°hNEϛcM: Ç}[±ƒ†õJ›†ÕuÖi#JÊCõñá,zd&âíÚFX}¥4‚cyÂÝgЍ©®Žh.:¥$Qú92®-õ’ìzp­–þ¬ éô°ݓ«Ö0'µòT^‰3΅µ¿ë­:'Å9à½+=\µ…ZZgA0^ÁUQä`„Õ­áě9@ê}=ʊ0؈,ŒÞXœ¹6~ÐÑuž¯¥P.„K¢>{¢ÔR ڎÅê€ã´px¡›éû™Ó ÝÚm§†©Î7ÃFÂà2Ð tmÄZ›~Z×vöÄ6#Nèó õBTÚ:XÝ® ýɜœlÜÝ á*]î¨Rœ>A 1×Ò¼]oAⱝÃÁe‚9ˆñÀHàñ3£Ï¬‹’,ËfI6KãYšÁû?¿`˜¹- be#UäeŽ’0Â8ƌž€mä½8†>>>>>endobj +221 0 obj<>stream +xÚ¥Vmsâ6þž_±Ã—$ÓØØ>J€o×&¹äæèÑ ™N{t:Â^ˆ.Bâ$9ýõ]Y61¯!WŒƒ¬Ýg÷ÙÕ£ývCD1¼k»o:;ùexÒ¼iAÃpBoڝV؁av6|D8~¥—íòåYÆ,–ÏЯWFg0á(2à,¹]Àdn'¨I±¨ñ[ŽÆ—ðA#ÊO¡LÂÐ흱ð)d!üõðéat^˜“;ÚMÆ-‚ ~&.°‰Ò3f{>†º.J%HZî헫«fÿóoÍ?éÓ»½íõû½û{ø)¢Ïßëa…Q;líÉv†öQeS½à÷An0£<®‡ h üãó½{¢MÃÑy™ÈLFå:=Lð„ ”l‹[‚¯ÌÃבžQ®äëé™9¦|ÂSfi;”f>Ûñ²Ø– +ŽÒ†p£4üú0¸/œr´àB ¶40Þ¬eÃA4ã0n²±ÌæfwÄ©’–qY‹›¸È…o´AU&gB,[—l#‰"ªÒ8· h›.3_áÕ"NU†˜F˜+cøX O¿³Ù\à´¢¸â¯‘K–Sshþ/±ÅҍiTùޮ쀍Õó1u/-ÁÌgcJ„ò.,*¸.fלՊ·ú1° Š6¡é©dp78m`dÁ +Ö5¦ÈŸ‰™‰V³z'yÄ.ė^“‚Vô¢I¨µÒÿ5…:ëÁí¤.ª"_YngDܑ0£±)½ŠÉ¤˜å‚yæLK.§¦:ØûÄHà3 +XÉfå½â«Ìjãç|I¢fŸ-›q·ÛíÅôíô’N©aðQI¾©f91G'ñô +ÍÓG´§î8žÎøž†¯zLâ^”Ô=&ÿÛcÒ£œ×<.˜”É…ðbQóu¼ Ñðv9/±ä¸,IZš$êÍÌ(i_nvÇõ&Fï¥ï6PiškY¸î´Öó»<þ±íÑågP“Šì>€€U0Gíî50ŠÚ„¥Nkßv· v'ýUI¾˜¨xy›×«m¯W8ΧSêþ5Á:ÁoÖj¹5B,Ñëל‚jwÝÍ5—–" ^}²^éI]ª›lCœxF +C·™p¬Ûa²C3ެ­hòÒ¾OZŽPõš0lašnÉbPtŠÅï6ߪëÑt´ýfV†$rE]*a7D±£—ù +¡áÚm\âz¡'JµpÍÄ_šuŸš–ÎÜì¡á«<«i«‹ (¯z©šs4‡¥¶:ÐJY¬]*ùs¥i48¿M¸Êp¹«kÃ\•dÁ¥ÿ‘­:?„» ,U‘°Æ3] Ì˜‹–¯‡b+±C;y"_|*K|Â*{¬Sæ·:Dc»Óõ0Åèw¯&vᦣ÷ٌKêÍ,]™Ðg’šµP +o\&‘³JZn±Eä$ÚÇ_O~?ùlX¶Ìendstream +endobj +222 0 obj +1085 +endobj +223 0 obj<>>>>>endobj +224 0 obj<>stream +xڍTËnÛ0¼ë+¶§:@¤ZŠkûÚ5Ð\D½(hqe3H‡\UèßwW8•tșݙٕ¢æü¤°Êàf E}Σ›¤)ä%ß,׋d ¹žå„«üž/—Ãå¬ èû£?ƒÒ`¥¡p–”±ˆYVÕ®ìޅw3yý¶Ýç#ÛãCƒŒÝÇŒ…9m ˆ¼Ù5„wW\Q„fW"ԂœCœÞ$™¦ƒ ,§B(‡£7V +'*[&‹glÝ»]lôŒ1lSïØÒ`ï¨ö;ä>}CÔ |DPÁc@rz{@‹˜Î܉ú/¿¶·ÀÈ-û¤Î½w^†ž’€+ùu€ì£|Í£ŸÑ?]fmendstream +endobj +225 0 obj +509 +endobj +226 0 obj<>>>>>endobj +227 0 obj<>stream +xÚ-‹± +Â0E÷÷wÔ¡5‰¥fU±› ô9K°©FÒӈ¿¯Q¹w:œó ñ™Ä²Î¿ ´aZ4R‚{ÈJ—+%ÀÝl{:´hCŸ^&Z¬»ÁnJѤ'ìÍø4~Îw*~Qñ¯Ta%D©ð|³°1†xöáŠÆy›…ӑÞLû&†endstream +endobj +228 0 obj +128 +endobj +229 0 obj<>>>/Annots 25 0 R>>endobj +230 0 obj<>stream +xڅTmkÛ0þž_qûÔÅvB\Æh»·@7¶Ö¥ÛGٖc­¶äIJÝþûÝIÎKcDbßór§çògC„ŸÒæK(»ÉU>™}Ê ‰ ¯ñ>>>>>endobj +233 0 obj<>stream +xÚ­SˎÓ0Ý÷+ΩHÄy´JÛÙ ÎPÄ,†Ç4#¶ãÆNcšØÁvõïÇNZ h„’Edßó¸'÷~ŸÄˆÜc–ú7¯'×Ù$|¿B¼@V¸›t± )26ý z¼S¸Å’…Ø·šãæáó…ÒØ®ï®×o_gßtŽ8¡A’’¹‡f +ù@o [ [rwTUªrïjëšJv5òEXy:g.H¶W¨$ƒÇ¾y SïL£Tõˆ°£:ÌÛÆ„;š¸d¡»Ãæc¶¹¿´ dgsNû¬4^Oϔ—¨)­öšÖÆv‚q†^ØrlÆRm}¿œ%$")Á'™sU‹’v5eÜ÷ìù]LñŒ$ÞI%äa(Ê©Dk†’g¬ýîªæ¶T bŒ‘ñN8­‡ûÛ!dG§Y!-׿…DÊjÇ4'Ád¬™ž À)‚ÎÇ~†—Å¥2VҚ‡Ï£!?ÿ†ï;"Ëÿ)ß+}ØkÕ6á¿ya, wcË|Ž5”¬Žœ3«°ãþ¹Ð‹!ô¯B2Õ˜£±|˜× EÁ5—?¬‘Qry’ŒçK—A¼š;6ìÆV¶§nSÖ>a¬¦Viƒ;*[:Ìd0‚EyT²ô‡‰#Y"úûUÝd“/“'y(µendstream +endobj +234 0 obj +475 +endobj +235 0 obj<>>>/Annots 69 0 R>>endobj +236 0 obj<>stream +xÚÕ[ÝrÛ¶¾÷S𲽨B€\:öq§þ%V@‘h‡=¢èRT<~ûb± p,@=O2ãx³Àgí.°¿ðßW¬(í_VÔ¼¨T±î®Þ/¯Þݙ‚—Åò¡`ÒªÅróÝrõiÛýCqÓïÆf7î¿_þuõŸåU¹(-|aðåã@ª’ ]t…ýG±-îüÕúá±xw' ÆàÇÁ>e—Ú÷ÇÐ<¬Ö üªZT–eÿs1û?ì¤V¬`V<Îʪ¥f F©åݝ %X3(^YŽøþe?6]q4Àéìv±1*ñ í÷/Íð¥mžN°…™‘Rsz+=G]¡…• ’´Åʅ;¢·ýúÐÙ£yZ_Á~«/^[DhÈ÷x‘¾ø‚ÏC_,yñ¤®ìW«)ûqñûã›n™ÔN>–PÔq»ÕSmï_„…\‡ñÃiŒ`_WHcObBl·½Ýíîñ4X°¿+Œ´=#¶8çÒ»­p¢\Ô1ñ¿>òâ J_©ŒóºRڃÄ[îEÖ%:Ùåç&¡ñ Äj\€~CDd{¤¼«õЁñC<äOx½ 7sÿBæpórʗʹaTŒ#&%e>ø •+µ<"¾‡j֟wý¶|@ÉìÿÎ)JŠŒºDå¼°•I¨KtÁ?÷Ÿ\¢ÁÌüs€œÀUiÝfWØCï‰@`{!8ˆw³]í÷ÍóžKœÖzwp¯ÊÝjGÂ2wÇïÚíØ NT‰å¬Í›·¬œ_S‚‰#qK8Éf8}ÿƒípÿÙk0âÜíÐ~!ýÙÓ¤æ¦?™V™0¥ssZ[Ó#1©L†>î·f|î‡ÿÚÈâ|Ÿ§É”LØKÀ)%ÃïßHɄ’èx:)ó`.{ŠÐK(¹´ÌÃ(Hu#bÎûC»Ý$ãz€`E,m€ŠàˆMp«Ý&!Þ´’ó¯ÔE|‚úi·WÛmò³… RÖGkxay¤µ›?ÿ¸wî袗©Î\éKÔuEÄ[Ižg«)@²°PE°ÄF&P¦`>ˆg1 òÌ}ÖMÊpÓv8ë D`~C»m÷ãÐ~:Œm¿»¨›8m¹šƒåªš²ßÊFE¤|¡n…©4úõÍ߇vh:ßdQ僆R“²+cÐç<ìvMOû1.éÍ/ À´¦ƒíLAòƒÑ‹4m.æt:$UZN! ‰)—«´úWèñ"#¶:'yÆ!³Œaï`Þ·»Õð’²×´n$ã˜_ N¢Ë8$LH+©1õ¶ç ¿#!­¤AïZ¥RæòÆ ¹„’KH=Œ¯?± '[Cî ɍ؄öáКäI’“€Â¼þhÄ'°_W»Õ£ Û.j³ËFm–i©WBúþ‹!â­4² +}~¾q印Uj„HlBÚ>­6]»K¶ +ë#4he G|‚³ Egë +ìÐÚëyÙL)«öŠ;×_CƒDà*mbèÜþõ&]t»­¾¡ÄŠ ˆ]Qt›Q×<†">AýÚoڇ—t¸ 0|ê!úIzÁI_Âf˜I0ƒî¿dG*È$¸ûÄîÓj ö‚¢!2DHv‡º­ÉVÃ&¥äi?(á  ^Ög†]ÁKý.@¸¸ïô­㙋UâÄٍð.V©|mÕõ_Ò9È´rG—…hÄWQKϟ޹ŒTsÊâGÆ®¡ˆÄ¤,nª3cm°Ý÷+#0â\ØÚž]¿’e¦;¼Æ¡±2ÖÈHÓ41¾oÆô,ØnªZ° Ù-YI›±æ~õ±ï¡n›‡Õa;¦kîé“1 $£Î†+»ÍE™µœRqá"XNÕTh«!mº`¿¹Ð"0b×çÄÜi3”îÍDPÄ?~²þé)[,*M èÔ³ ¹g˜MÒCq$³Iw¯×ëæiÌ¹ó ‹•àœ"0-»¤'˦{ê‡dÛ-¯mŽØSã% u2«Gu1$j¸¿HLêbZðDZ2m†dÂq}^‚|ýՙ¤ÑÒÅß]0•®¾±éêÚSñ ý,ÄúÁy7¦æòNó_ɨð1„1ÖH2*z ñKk£ÂŽÞËÌLʬ„6ÁJªd¤…F÷ö~èŸ÷7¦0³yt›¯¢7-¤ñ*ÿœÂ‰w½Ù Íg»úâ0!z)ŽSxWÌ#x)ÎÏïx$VB37‚"><Íú0´£{ÕXA;£ƒÎ2CpV҈ŸÁË{¤‚sP҈ÿ—~}ôÁ— þ/Ê»\ÇÄ#~Cãøß‡ 5Äì^õåÄÓ8w~XÇãyMÃïëí¶ž©ÎH§pìl ©ây¸¢óm³sϽ°˜Ye™‰¿¤)-ƒJHʨK/ÝѼ>ŒŸ—/Onœ.*{„g"!3¹‡#äUÀŸ8"|Yƒ>ds-VNÿ¿Çý|r®#ŸÂi¶ +Âý8ô‡§ßV³^}Ùß @™&Êãï²iªRÁ*ÊP·^(þ-Gq ãOx*°ûa_Øòü°Úb3næ5ÎYZRۇ«ÌÝL“endstream +endobj +237 0 obj +2255 +endobj +238 0 obj<>>>/Annots 83 0 R>>endobj +239 0 obj<>stream +xÚ՘ßoÛ6ÇßýWðq{ˆBRü!>nÖtV «]ô±ÐÙVaY™¬,è¿#y’(µ¦Ü—ÆK‚ đó¾<Þóς +ߌ¤ÊþlªÅëõâöÞNÉzK˜4DiAÖ¿¬ó¿©·ä®>¶Å±=ýºþ²x³^ЄÁþböׇ·Dó„•Ê$#a)O$Ždeñ“͎ÜÞ Â˜ý@Ía®‚¹ð‰«¯§¶¨Þ6õÓ£ý,E[Cò‚_̜õö ~sž(ð[ÊÄàÝyOa ܗ åYP°¶"†MAhîPuSåþ4@döò +M¾8 jaêFè¨ F~UYIûõ±pž +“¤×áéœ{Ò([랄{àGƒ{Òhwîmêã¿Î=ɯ¹ˆoÔº¦Œ»â¸àÿFÇnï%^g˜¤©¿Íò|¼ÐIÃɎhÎÚQnÎS‚•pýÄtSÞÜqÞ7%d±&rE¸)šõþv—P„ÛZn6õÓ±-;w|éµD§?Æ4ž²¤T.Ó¨ ҇ôÙåeH^RjŸq>í‹&’½LE´½Î#&š‘ÕÖçAÁZ{ܞ_HB»îRêñ!Ár€±Ì^ÆÖMèöµx.·Îô"v0œ€°?ë],˜¢SÁ`BèåÁg@n#ï…bl6 DêRº+T~0Ô@)„Ïèëý\ ì8Œ*{6!íˆÊ7›âtú|ˆê@|µcd7™Vi còJ +͜è)u…Æ+ãè)óuæёcŒ ᐃf$MS7qÉ„½s*Ñc ÚØ ®~-ٓ‹Ñ¡ªÐ^t7Dgم’#ÅdS +šç1ß3zgÌêMÇ4´gµ³ÿÚ¶ß†b)€@òƒï4f—*—±\Ðg¦84#'Ör˜€#l9sLÈùx‚öà<+X-•Íî#š‘u÷ñý*ÒO «­Zbº/´#ë¹l÷1©D°/ّMÅáÎVËw¯—î1bƒíE‹ëøåZ»Z ìÛʾ×÷ùŠðiŸ·‘¶g T¶õ×c$šUžHìÙ {Ïš#ڑäô~åÞDéõ¼þf¥WÂèv†¼)”ôá÷ú9¢÷°ô¶¥{ÄA3’~‹µ™ÃZ¸xNÜ„fý¹uÃRÛ~ãÚtW·åî)ÖH‡ û0â½p}g8r҅Bì}ÄåY¦¡øŽqð íaÛ:ò8 +W„Cž3N蜅tåb4¥?!BgƒO2W!}ˆ¸A|òÒÐCŠ‚æ 1>:B š/ ;¤`D„´ÿ`Ðu<÷ñº |¾…«mÛffÌ D\°¸¸ +'ðIR´eé'„\f?lØ6íÿ±™a!¹w¯&\e½l«zÛ>çpˇª<–§¶ÉÛº9‘wùñ)?XÞ Tê͝e‰òüµø ©jxendstream +endobj +240 0 obj +1081 +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<>1<>2<>4<>]>>>>endobj +xref +0 300 +0000000000 65535 f +0000000015 00000 n +0000000228 00000 n +0000001794 00000 n +0000001868 00000 n +0000001950 00000 n +0000002028 00000 n +0000002105 00000 n +0000002184 00000 n +0000002260 00000 n +0000002341 00000 n +0000002400 00000 n +0000002452 00000 n +0000002537 00000 n +0000002561 00000 n +0000002666 00000 n +0000002731 00000 n +0000002816 00000 n +0000002874 00000 n +0000002957 00000 n +0000002995 00000 n +0000003055 00000 n +0000003139 00000 n +0000003163 00000 n +0000003214 00000 n +0000003299 00000 n +0000003323 00000 n +0000003427 00000 n +0000003532 00000 n +0000003637 00000 n +0000003741 00000 n +0000003846 00000 n +0000003951 00000 n +0000004056 00000 n +0000004161 00000 n +0000004266 00000 n +0000004371 00000 n +0000004476 00000 n +0000004580 00000 n +0000004685 00000 n +0000004790 00000 n +0000004895 00000 n +0000005000 00000 n +0000005105 00000 n +0000005210 00000 n +0000005314 00000 n +0000005419 00000 n +0000005524 00000 n +0000005629 00000 n +0000005734 00000 n +0000005839 00000 n +0000005944 00000 n +0000006049 00000 n +0000006154 00000 n +0000006258 00000 n +0000006363 00000 n +0000006468 00000 n +0000006573 00000 n +0000006678 00000 n +0000006783 00000 n +0000006888 00000 n +0000006993 00000 n +0000007098 00000 n +0000007203 00000 n +0000007308 00000 n +0000007413 00000 n +0000007518 00000 n +0000007622 00000 n +0000007725 00000 n +0000007828 00000 n +0000008146 00000 n +0000008251 00000 n +0000008355 00000 n +0000008460 00000 n +0000008565 00000 n +0000008669 00000 n +0000008773 00000 n +0000008877 00000 n +0000008981 00000 n +0000009085 00000 n +0000009189 00000 n +0000009293 00000 n +0000009397 00000 n +0000009501 00000 n +0000009609 00000 n +0000009641 00000 n +0000009673 00000 n +0000010427 00000 n +0000010475 00000 n +0000010523 00000 n +0000010571 00000 n +0000010619 00000 n +0000010667 00000 n +0000010715 00000 n +0000010763 00000 n +0000010811 00000 n +0000010859 00000 n +0000010907 00000 n +0000010955 00000 n +0000011003 00000 n +0000011051 00000 n +0000011100 00000 n +0000011149 00000 n +0000011198 00000 n +0000011247 00000 n +0000011296 00000 n +0000011345 00000 n +0000011394 00000 n +0000011443 00000 n +0000011492 00000 n +0000011541 00000 n +0000011590 00000 n +0000011639 00000 n +0000011688 00000 n +0000011737 00000 n +0000011786 00000 n +0000011835 00000 n +0000011884 00000 n +0000011933 00000 n +0000011982 00000 n +0000012031 00000 n +0000012080 00000 n +0000012129 00000 n +0000012178 00000 n +0000012227 00000 n +0000012276 00000 n +0000012325 00000 n +0000012374 00000 n +0000012423 00000 n +0000012472 00000 n +0000012521 00000 n +0000012570 00000 n +0000012619 00000 n +0000012668 00000 n +0000012717 00000 n +0000012766 00000 n +0000012815 00000 n +0000012864 00000 n +0000012913 00000 n +0000012962 00000 n +0000013011 00000 n +0000013060 00000 n +0000013109 00000 n +0000013158 00000 n +0000013207 00000 n +0000013532 00000 n +0000013684 00000 n +0000020039 00000 n +0000020061 00000 n +0000020156 00000 n +0000020258 00000 n +0000020278 00000 n +0000020433 00000 n +0000021348 00000 n +0000021369 00000 n +0000021501 00000 n +0000021816 00000 n +0000021837 00000 n +0000021977 00000 n +0000022895 00000 n +0000022916 00000 n +0000023056 00000 n +0000024488 00000 n +0000024510 00000 n +0000024650 00000 n +0000025541 00000 n +0000025562 00000 n +0000025675 00000 n +0000025872 00000 n +0000025893 00000 n +0000026047 00000 n +0000027023 00000 n +0000027044 00000 n +0000027207 00000 n +0000028208 00000 n +0000028229 00000 n +0000028360 00000 n +0000028854 00000 n +0000028875 00000 n +0000028988 00000 n +0000029183 00000 n +0000029204 00000 n +0000029362 00000 n +0000030162 00000 n +0000030183 00000 n +0000030351 00000 n +0000031518 00000 n +0000031540 00000 n +0000031698 00000 n +0000032742 00000 n +0000032763 00000 n +0000032876 00000 n +0000033073 00000 n +0000033094 00000 n +0000033243 00000 n +0000033936 00000 n +0000033957 00000 n +0000034115 00000 n +0000035204 00000 n +0000035226 00000 n +0000035394 00000 n +0000036427 00000 n +0000036448 00000 n +0000036597 00000 n +0000037432 00000 n +0000037453 00000 n +0000037603 00000 n +0000038461 00000 n +0000038482 00000 n +0000038632 00000 n +0000039980 00000 n +0000040002 00000 n +0000040142 00000 n +0000040956 00000 n +0000040977 00000 n +0000041090 00000 n +0000041285 00000 n +0000041306 00000 n +0000041455 00000 n +0000042244 00000 n +0000042265 00000 n +0000042424 00000 n +0000043580 00000 n +0000043602 00000 n +0000043742 00000 n +0000044322 00000 n +0000044343 00000 n +0000044456 00000 n +0000044655 00000 n +0000044676 00000 n +0000044830 00000 n +0000045523 00000 n +0000045544 00000 n +0000045693 00000 n +0000046239 00000 n +0000046260 00000 n +0000046414 00000 n +0000048740 00000 n +0000048762 00000 n +0000048916 00000 n +0000050068 00000 n +0000050090 00000 n +0000050145 00000 n +0000050250 00000 n +0000050394 00000 n +0000050497 00000 n +0000050602 00000 n +0000050767 00000 n +0000050875 00000 n +0000050990 00000 n +0000051095 00000 n +0000051203 00000 n +0000051311 00000 n +0000051427 00000 n +0000051525 00000 n +0000051694 00000 n +0000051850 00000 n +0000051950 00000 n +0000052065 00000 n +0000052189 00000 n +0000052297 00000 n +0000052417 00000 n +0000052582 00000 n +0000052689 00000 n +0000052855 00000 n +0000052960 00000 n +0000053078 00000 n +0000053194 00000 n +0000053322 00000 n +0000053453 00000 n +0000053575 00000 n +0000053742 00000 n +0000053862 00000 n +0000053978 00000 n +0000054136 00000 n +0000054228 00000 n +0000054335 00000 n +0000054446 00000 n +0000054547 00000 n +0000054700 00000 n +0000054796 00000 n +0000054902 00000 n +0000055008 00000 n +0000055113 00000 n +0000055222 00000 n +0000055332 00000 n +0000055446 00000 n +0000055545 00000 n +0000055681 00000 n +0000055779 00000 n +0000055877 00000 n +0000056036 00000 n +0000056151 00000 n +0000056271 00000 n +0000056390 00000 n +0000056495 00000 n +0000056644 00000 n +0000056746 00000 n +0000056881 00000 n +0000057003 00000 n +trailer +<> +startxref +57230 +%%EOF diff --git a/doc/sam.shtml b/doc/sam.shtml new file mode 100644 index 0000000000..4b8aa16962 --- /dev/null +++ b/doc/sam.shtml @@ -0,0 +1,1070 @@ + + + + + + CUPS Software Administrators Manual + + + +

Preface

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

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
  • +
  • A - Using CUPS with SAMBA
  • +
+ +

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 +
smb://[username:password@]workgroup/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. + +

A - Using CUPS with SAMBA

+ +

This appendix describes how to use CUPS with SAMBA. + +

What is SAMBA?

+ +

In case you haven't heard of SAMBA, it is basically a software package +that allows you to configure your UNIX system as a Windows file and printer +server. It also allows you to access files and printers on a Windows system. +Like CUPS, SAMBA is free software. + +

SAMBA version 2.0.6 is the first release of SAMBA that supports CUPS. +You can download SAMBA from: + +

http://www.samba.org

+ +

How Do I Configure SAMBA for CUPS?

+ +

To configure SAMBA for CUPS, edit the smb.conf file and +replace the existing printing commands and options with the line: + +

    +printing = cups
    +
+ +

That's all there is to it! Remote users will now be able to browse and +print to printers on your system. + +

How Do I Configure CUPS for SAMBA?

+ +

To configure CUPS for SAMBA, run the following command: + +

    +% ln -s `which smbspool` /var/cups/backend/smb ENTER
    +
+ +

The smbspool program is provided with SAMBA starting with +SAMBA 2.0.6. Once you have made the link you can use the smb +method in the device URI for your printers: + +

    +% lpadmin -p printer -v smb://hostname/printer ... ENTER
    +% lpadmin -p printer -v smb://workgroup/hostname/printer ... ENTER
    +
+ +

The second form only needs to be used if the Windows system is in a +different workgroup. + + + diff --git a/doc/sdd.html b/doc/sdd.html new file mode 100644 index 0000000000..c49dc5e38b --- /dev/null +++ b/doc/sdd.html @@ -0,0 +1,490 @@ + + + +CUPS Software Design Description + + + + + + + +


+

CUPS Software Design Description


+CUPS-SDD-1.1
+Easy Software Products
+Copyright 1997-2000, All Rights Reserved
+
+
+

Table of Contents

+
+
1 Scope + +2 References + +3 Design Overview + +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.1. +

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 5.50) and an image file RIP that +is 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
  • +
  • A - Glossary
  • +
+

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

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

2.2 Other Documents

+

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

+
    +
  • Adobe PostScript Printer Description File Format Specification, + Version 4.3.
  • +
  • Adobe PostScript Language Reference, Third Edition.
  • +
  • IPP: Job and Printer Set Operations
  • +
  • IPP/1.1: Encoding and Transport
  • +
  • IPP/1.1: Implementers Guide
  • +
  • IPP/1.1: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
  • RFC 2567, Design Goals for an Internet Printing Protocol
  • +
  • RFC 2568, Rationale for the Structure of the Model and Protocol + for the Internet Printing Protocol
  • +
  • RFC 2569, Mapping between LPD and IPP Protocols
  • +
  • RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1
  • +
  • RFC 2617, HTTP Authentication: Basic and Digest Access + Authentication
  • +
+

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

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: +
    +
  • quit - Quits the lpc command.
  • +
  • status - Shows the status of printers and jobs in the queue.
  • +
+

3.2.2 lpr

+ The lpr command submits a job for printing. The CUPS version of lpr +silently ignores the "i", "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.cgi

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

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

+ 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, get a list +of available classes, get the default printer or class, get the default +server name, get the local username, and get a password string. +

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 imagetoraster

+ The imagetoraster filter converts image files into CUPS raster data. +

3.5.4 pstops

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

3.5.5 pstoraster

+ The pstoraster filter converts PostScript program data into CUPS +raster data. +

3.5.6 rastertohp

+ The rastertohp filter handles converting CUPS raster data to HP PCL +and supports both color and black-and-white printers. +

3.5.7 texttops

+ The texttops filter converts text files into PostScript. +

3.6 Scheduler

+ The scheduler is a fully-functional HTTP/1.1 and IPP/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 Logging

+ The logging module manages the access, error, and page log files that +are generated by the scheduler. +

3.6.9 Main

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

3.6.10 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 printers and 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), "F" (filter), and "E" (enable and accept) 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. +

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..6107a876fc --- /dev/null +++ b/doc/sdd.pdf @@ -0,0 +1,757 @@ +%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[12 0 R +]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[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 +]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[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 +]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<>stream +xÚìÏsë8rÇIŠºÌ‰öŒî´üt§çyšÝ­ÚJñÙfvçÖ$ÁÊ!•S*Ç6•üÿ±~X"H€èn$è5¦jêÙE|ˆÆ·@ƒúÇOßòýÛßò?=å¿ýžÿçÿô,~*ÅOÿÈÛÿù×?þøÛï¿ÿºÏÿü—_Ÿò§§§·kýñõ¥ù÷¯|­ÿöœþº?•ßNå÷SùË©¼œÊ¿žÊ¿üÇ×?òÿýŸÿû¯¯ÿ–ÿíÛ׿ç‡oß¾>ÃKþ=ÿãõ§öcøä²+âõi»Ý>ÜËÛ?¶ß_—Î%^¶wY¤*w÷¯ËäOj¤Üöû¸ē‰é½Ü?–KáÂC]о/ëå!"—x[ÎõœE¼r˜ë‰KåÒ!˜¾rÛg޹^òȾü\ÆÕÊÏ3s=GžJRÎÉõ-òVâÃl\ŽuЄõV¾ÌÂ%²( + ‚B¹ü29×$X,0X –€Åƒ %ƒ/° ¬(ÚMÄåÝoÙ9h6×ÄXo`å\ûhò’LÀõ#𡬼sÕÑ,åÏ\M6A!|…gi,A +Ú Ñ ê£s5Ѭåà‹+›— 9Ä`™ãÅ`ž‹,öD.1?V{àÊàŠRç\uD98æY\‰c®}HÙ8媣`Jé++D91WT蚐°ŒÒË TÔ  LÔ‹Š4ðZåªBÃ2t,OãQ ÔxŒsÆq‰±FãzX¢Æ#F,Ï%£FL×]w÷Ûí—×cy>|ðÛa0IwÅ÷_†ƒüxÂ[‡ÿîŠG’þÅ˃ŸßÝuoœ*=[ í,¸ö~ºªÛk[ça=xì.Bú±àæØ\ìPƒ–.Î$[q¹¸¡==·aMJ&³»XéԜ.K™\¬@ž› É貘ÇUùÑv‡]¶cqeSÙà՛eN¤ܯjؤ½s’  ®|²¡ÅϼJé\Í Xd°˜ÎEùØÍÉÜZ9ƹfÂ"‚­¨\Õ FÈ1ŒȕυEÛи'’ –Y¹0p7ñú¥uZj+Cg‘¼c,Òé« …«rÎX•½ÅÍÁ‘jÄ¥{.B J<—°ÒlKÃ7D=Ì:¸ÎåÛÁÉ %i=•œkˆàBf½ .Ú`Ø`¹Š¹2O”,Á W­Ç’ó ìÍПR4q‡ãÚa…„–¤8®´&1Š«žÙ#3ì€á«aÚz/8 [c¸²0Dƒ¢õ ‚«æfóuXiæ*B J‡íÌ\Y OjOjäªÃê.d‡%F®"°îBú°ÒĕÖ]È'½1p5Á¸dZ“RW\wá¢ÄÄÀ•6ºÐRVŽr‰» 7æw£\u€Ý…[FJG¹*OŠ…²¢d”+ (2$*ÇVå'ÆB ÃRåÓ©¹Z’ Wå“s! q5ÂÀÚÛ=W¢È£­ÔrAˆ"v@;-W¨jàLi­ã¡ªnè¯t\5-4”=Ùí§ž±¿ÿ.Ï´’T¹Æúù=¾aÀ +¢6(®–KH·Kh%ºÖRÕÓbQ®•–ër›®Îa‡Àà ¯Çé¹ £^ >ÜÌіœáµCrí´\MçùÖ 1£$UsÑys¥Z®³í%·NH)}¢æÊ‰Îkœ+ÑsÝ´BPf=ègŒàp‡åz7.×MÛk¼b”¾Tq5ÔÊÀµÑrÝD° ¬•T؇ô¹WŠçZ鹊÷G”Q&ß V<זByW¤çª/ŸÕPÌ1PRWF4C#×NËu¾×úü+ü’QØV +.A5C#WªçڟòáªÕr[¬àª©fhäŠõ\盽§5Rì•K,×êZ[Éu6Ž;êÊ12BªWNZ,×:{—'%WG¤(³ÔgO@• ž«x j®Š5K5†ˆëWC6Ãq®ZÂp ÖbI…Ó5 ÊFÒâ¹Ä»Y¨¹®&EZ,ip-â\9%pžê¹*֚Nè(; +\n£á¬5;c+\ŒôÅq®æ" +®K‰kvª‰@“¤¥pµ¥×qgéB™ÐdcMãº(½Ž«àôWòD@“ë¢ô:®Œ3¾êÙwCÅuQz WÍÛÃÈ0’ ¤h#!r]”^ÃUðûMÏ%s Æð2r•^Õñ6g +ÌÃ’lì¨\g¥Ws5Ì]Œ +㘁´¶ÑR¹ÎJ¯æ½ØER2WÁ^f®“Ò«¹rfæŽÀ8f DQ)ëd݅~^¹e¢IàkSYŽ­\§Öç*®³Ý Fȑ#š ”(ªT?º²k ±ÌukDŸ+?krN7Ä="àVÌµë>š>h¸Þ;а›‚]†Yw¹k6+IlºŠšô¸ Wuáiè†X!dr¸Ñ˜ÄjøCýsȵèÝJ´§•¸rŽlH[âã‹:\…’K\[°'¢@Ø¢C­I¤€]Ÿ«VrU×Ê=öEèà£ÃDïû¯´ùÖṌŸêsí¯#èùVž«áxåÛ-â;^WÈ\OÌɱonn0¾d=äª\ÝT”‚lˆ{ó€¼0ÚT¹WWojò$ ð\{–l lbÕ¹.¶*qeÝKž„‰×ñÒáÊY²Ñ˜×Ó{Šyq—KΈÚ{ÈhzªX¯üPy8Å:F—« »òúh9ÔNþnï5ùÒ*¹Ä€+“,¯ñª è¨Wo'ÍéŧñýGH©\SßËy°†ÇeŽæãvQ°2Ÿ,’+çEQÁse¼(*t.a#‡s5–r*W͍çª>š^¸ +vt6מ͕4™¿peM/\œ¥ùp‰'óg®úÃÉ<–k2ߝÎ-‡͋ó·•Ü:\[æ»uîªßFwÒ²ßmµwpœOm›.Ò,²Î-ï\·u›þà,•\×FÍÕI¿\¹r¶ûRãkT§×ćk¥äjÔûËÛ}©4fÜkbÄኔ\¹z߁¿h£¶W]nj¯‰;×NÁU UPn9Ár­4áËNŕr¸RW6|ŒŽ¹Î«Ëë51áp%C®wшﲫÝÊ-§h®š+Vqõó¡¸g¯r~ô'/ÙÅlp\ëQ®Ó¿^òHjÁZv,¥Šk£tEr<Џ¨ëdÞ7ÛnlÌ\—᯻?"éx@·‰+×à¢Zr—Ûj{‡àꤥÈ]|Ëíé71âp .’7.y<€ +£®[‘"K~­lâŽÃÕ¿(—óM +-áðì8—Ðpz®”ÃÕ¿¨7RNf™*Œj1\·Ùÿj®˜ÃÕ»¨ðTà¹b\Šã|f.ÅEußÁnßÊ#`ÂÃĞk¨Šã|f.ÝÀT5_ŽÜp ×^­óŠã|®áE…ÒÁ&ŒJ[=Ì®9·r‡Çù\Ër¥#Bq­Q\µÚ՚8JqœÁ5¼HËU;â*”ñÆË- é5qxœÁ5¼(S:"×Ã%¢"ÎSÇù0\ƒ‹´\?Œê´áò;ô¼RqœÃ5¸¨[ývGסµœm”MçÃp .Òr?ŒjÕ£YU4ñ"Ú4®þE\-š+Uý6.5MìçCqõ/Òr¹ê^,ÕMìçCqõ/Òríùáa«68Íòþ ‰ýã|(®þEY/Mõʕ;ãŠK W'T•šØ;·ãê]ÄçJ\ñ®óۋ_¾,{lÔMìçÃqõ.Ê;Š-qen¸:ù‡Ýxã¼ì‘ª›Ø;·ãê]4ˆ£*,WÚâæ)­Š«ó~(EO¢Må’/Ú÷#¢âÂùåªÇ¸äã|H.ÅÀn÷X®µW£‹ç¯AeNä’/ªúC%;s Ï\BsŠCqœÉ%_T÷$[DX®W;Ê.é"Ñ Í« ¸—|Q&°üÂeÎ=Üy䒎óa¹ä‹ +E2þW=/WÁá’.ªn»Ê·EÞÙ¹j—t‘è¶²¾Æ6ÓJ\‚Ã%_”ßö¿ž#W铫{œÍ%_T ö+Càª8\òE½H0?qÙL—Q\Ù8WÃá’/’gÆé>®Îq>ès¥”ºór=ŸÞa?bšK©;3×Cÿøšü²¡ÎæuÕ»ꝪHqPJÛ:k®|¾!çéw·§†u\y1Ô׏áŒF~™WsÛìø9QeäÚÉÔ—Pì(É/4¬®KüuòÈȵ™‚ TSë¼;Àz齺 ®u+ M?\™j« ºã “Òdúu\©l)^¸š÷§»nÝî«ko»õʺ ®Dºµ®êºQ(¾unڑÀ[v…².Ÿ«öÉUtv¬÷7ïÒqY·äsM]Õ2¿ú®òöNå“+ª›v^Ȭ©K㊯ۧoƒ8ñƕu—áòžÒߌ§©KãJ®£0qÙÄóҟá¦×VËIÚªº$®Õõq¼=™t®êöÓ5ä$mU]WÚ}tk;.CúáõÏÍÝ[ÙtĪ윑Ò×%qÏ]ÓÆ+W¢ûѧ“T<¶ÔçÊ/ƒô8„wÞ¸2]:ÎeO¹éÀd#©;x®ýåóŽŸ|ðÆuŽš¸1‘†‘¶.‰«¸ÈÐÑÒKo\—½Îûƒ:À:eR¼Ë¹¶.‰ nÙ¯qëë¢Z{þ⇬ã‹õu•\ÃÄÎEu¯G÷叫“Òkmñîm®¾X_—ÂU_ `ü`;®±}½n=é½ÄÕ0‹V[—ÂÕ\~<ºeK®±}ØByŽCš—ƺ.]_ˆ¾ç²Ú_ÚÌÒ|Õ¢¯Kàj/Žùô[\½,Ú¸ôdЍKá:;æ“[öÉÕyіL¡ú’9]] +×Ù1×'ï“ëý ì —J•l:ZÇuvÌõ©¾—1ïë9Sš\ùPÔuñ~ùäËãÿc—‹|¶—‡á¤¦ÒLrTu \ÕÉOnÙ?×­µ«^(u@Õ%póÉ-OÁõ. +‰vЌÕ%póÉ-[raß-Z‹ÁX]—x÷b멸n‰×f®^]×Ù1ŸEr”Ë&ûø*™ìе\cu)\o&˜4·õS/\²{ãb§®.…ëM2âúì-¹JÜú¡k¬.…ëØÓUt}Q7®D²­x”KW—Âçð±‰ËæÜM.ý9Õù±º®ê|²&±çڍO¿6ÝyÈJË5V—ÂUߜº7®ªÛŸûÞmz«Kájn³Q.›sˆçkãï·M­–k¬®!ž—Þ¶%ä]A ®qö¶ ©Ÿ,ŽÕ¥puÞ ë«™«õ¹F꒸r—Õ¹ìf¤jŸk¤.ƒ«´çZãÒmú¡ÿ VÑ×%qƒßxàjô +3àj¸ëQ2\ŸÊ(—Õû7䵘_ÚQ.}]—îý¬n¹:}l \Úº$®úêÓǹ¬²Þè!Ón”ØÔµ*–ïí¹Ê×ëMóU|–ïY +¶X¾ë“kz.ó떗ÉUüÓr•‹ä2/pÉe3aþ䚞Ëjb¹h®õ"¹Ä?-WºH.ólõA¹’ere0ðµü>ŽO®¸ö0ðÅ}Ïn‘\ðA¹ª Z~¯Ù\Åô²×å÷ÐÍULMÞá¾70¸@ªrÃ\ e’ºÒò{9ç*Š+[\Àa +%°ß{ZÀ‘›ì ù=Å¡­´e&=@~¯thG„â‚¥Âèo‘ßoXÀQã¸÷}ô•±mç˜Á8lc®Á9æ½Qæ#/Á9°Üè–ã‚s`™±Åš3‡}€²×ÀXcV@éK`3Ëڬހò9°ÊÜX@=€ÀXa6.@l`3°½9êT˜ËÍ"8á Kèmœ£ Jè„m®gƒú¡€S˜ „A:àª%ô¢©€ìڐ„>G˜ ‡bH}fv_ï\bAB/0Ò -Vè׋‘Ã]‡+_Ž V˜Ȑ+ A,0 +-V裥ÈaÜ媗#ˆ(Â-ôDˆ *âƒ-ôéBäpÝåB} Â(»‚-ôÇ¥€VÏP„#C̾:\ÕB")£œ· Å }ºÙHd.„Ð'‹TæB,Ýċu+_†pd8üƒ"âȇxà B8j¤—Â!Gl#´A `1Û¨«>BðÌØå +h)‚¸xí\Åú,(ÖCéÑg­¡% ÇÜ ýŽhIÂ1ó3?ú•‚+~€áï€d¼s°=z @KŽy>r’s˜y€Õø©bå™a÷H*:sˆH؇–(30Ê&ÐúyÖ9eˆιÈQDs‘ƒ²Ôā9£Ò7”AОQéI+Ò@½t>¥Ï)Mª’ζÚ&HšÔ¡9›!"li¥åڇkˆ´åhél¨vc! »ô™ ±¢g83âžö¼nų¢ †®@žâÌcˆñqCË`3Ĉ9qx@Ë`iˆf(Í4€ó`¦Ÿ¬Tԇ -g€M>kΩj-k€MœdY“½´¬6± +ÈcX]>±rz‹€5D'VFÔ +œéöÔ1GNÀY™8樼A:©ÔgB©œÇ Üϙ.H,8ޏÃtºc wàÊêd†kÍÁ…Tú‰:,c=càÔ4Æ €?R§é°ŒÖÛNÓaә_‚& :C¢Åqí±`»0ºk…äªé0‘qƒph­ ±÷UKó„ªY.´v†èuâ,øV­!zÕzìÓÝ ¹ð†èQ:j ›ÖÖãrfWŠØ ¬OKüñÍPË%¢¹-±±’.h­ ѓ&æV>¬­'BõÊXZ?Þ¹±´°öõ^†˜È,e \<1÷3–½í#×½{&ܸ¥rU¤s©ÍJÉ\"š LdöܹK0‘;¸)82‡i\o\´;¼•Ÿ'–‘P¬.t¬Â^¿¹1p1_uFÃÒÇàd}¡ãNSbé¥ +\EiW°/)áøf08Ô&[õ cœFwžÿf<[l2êR6W›qÀúßtŽ*OôÛø\‹+Š¿S;‹añcq€‰‹ÙaQt_zî¬ñ¹‘‘«ˆ¸ÿ¥ó/9k·6\"â—{”56¼OßYqYtØqœ=šÌñ…Ie˜>˜¹l:ìŒöªÿ짌ý¹K.ê4Li¯ƒ~/ÛÌæqµ¶\Mä¦ÜÝo·Û/¯oåe»}È,?mcÍå¢ÃœSþ#†KȵqÀe'‰³tŽ+¼Û9á +®ÃÌK_8.±´îBrvm¦(ˆ=$W›…ÄupÇU/«»Ð\¬•O_ºäj‚áÚ´.¹‚ÑzÜöžKdKÑxw gÑ q!Øý^ +—XŒÒ¸°DôÖ!‰kvKÄgиš…X!•kæø—°MäšÕ)¹/T®9½3eû‰Ê5c`OJš#sÍ6Ähi/t®™†1±ŒÁ5Ï#îí2¸fbÔ,%=pÍ`sM®ôT9×ÄÚÁÈdr‰<\)´ášRY©Ã\®éÀx™dl.FÚÏ$ŽËšk¢Éóā×þ9椰áòoŠü,M+.ß`ɧv\~UÑ&Yؒ˧ƒ¶Ê¶åòf—ŒoÍEΡö41qÏåcÚb™®î†Ë½,ڟ›pÂÕ +·¶øhß"7\o¶è®Ë’CW+Âé,—\ŽºìþІÆÕŠ'küâª-.¹ø©ÕªGw-qËe‘^Hݞ“‹Kæ–ʇìþ‹ë6øà"æÅÇ[ï¹ðÃõV^qÙññýw/·÷Æuê5ƒAÞm_}ÝÛ'ש۞¶wê~z|õy_ß\çŽ;žpØ>ÜËývûøúêý–“pÍPàÿÿÿârõä +äÿÿMŒÁ‚0ƒï<ÅÔÄÍm,ÀŽ*xF˜@`à ad›Þ^fbôÒ&m¿e´? `di‚3ˆÅ*²Ûœ®e µéý«± +råô0k­ž½6ÓVÞW”¥¥,Í1û¨ÎsD1 CD9N±óP[~ߥ5Ý£õî3ä1Nþ~̼X=Ü>>>endobj +147 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +148 0 obj +31 +endobj +149 0 obj<>>>/Annots 13 0 R>>endobj +150 0 obj<>stream +xڕUÛnÛ8}÷W úäµV’ïûÖÄI` íj#§Ø¿Ðe«¡D•¤lx¿~)¹v.-²H`CšÛ93gÆ?z…ø‹hÓpB¼ì]¯zÜÍ)i•Ã2™Žh•õ#J¹ªÅÕê»·FÓÖ:˜DAìíADËLT¶È Îl¡ªÖuDQԹƓÀ§Zí +CFåöÀ´ L˜b[¹/®‹ÚR¦xS"ÕZí X`µ¬"£¢Ê•.}~Â¿Ý bšï ++¸mUq•ՖTî n4l!:çU–ˆ{üºü‡].<Ó£±¢¤uÿÃÍc’~X_Ñ7¡+VÁ+ÊqØòp̻пöBï qø çß×þɔQ­´e)ð®ó‘ì(4¸]Çã ašy£ñ L@KK;f‚ÛU/ BŒÕ}DîãážfcÀG1>KŠÂ9pµO’R7ó]£6B¸ì…D™Œ6GúeÖËDH;Ž‚ÙEÚ7ü/<à?ƒá ÏCôö¼ÃvË̑ғx­²†[Ïúv‘}²Êu¶TÊ c¡¦³sc’—’ë-“²Í^T™ÒÆiÉåx?UÔh# §”óԜ´ºI~ó¼úIHq„Ë/²¨Ôk…Î&è´y҇O‡Ômª¥ó«„=ËD­âJB¤ËÛÕÝ`™$)kÝ7Ì`£”b[çï)Òwµñ4èG#%ÈðÅR|v¸|HlÁ„Sèºÿ9Y|¤‡»›(šÎ×W)…¼aÿ"Œa[A×Rñ'¸¥_®ÕUøT×)^ +¿´**»…”F½(išÚiÊ:vGZ`„xțŠ»a0YØã›ýaYfm9(ýÔ2¦Vã(;‰26õwäÌéâ°`Ód eâBÊÛÑÍ_`H& ueF¬®ewâ 5U&Úµ|1Øcê\6ínóÆXUÿ¢ö¾;1*§û¯t¿;C_÷y£5 >>>>>endobj +153 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS045×3V072PIÑp VÎO+)O,JUpI-ÎLÏQÉE™%™ùyš!Y\ººP-F 13=30ßP!89¿ $êÂÈøÅ Ÿendstream +endobj +154 0 obj +113 +endobj +155 0 obj<>>>>>endobj +156 0 obj<>stream +xÚ­–Moâ0†ïüŠ9v%HI r£PZVE͒´§½g^%6k;jù÷µ>ʖJZqçyçãQþ6|h›½:!Тq“4.'×´!É̝°×…$½`ŽJäՏä;â÷ª#­Ð÷wÈóaôÅ0´,k¢™àÕñ.øþöxzŽ™¬2‘çâ…ñeõ`úþA` +äN5…ÅôÊ\ڝT`º}Ğý;{p¬|aZ£YÔò=PéÏز”•ÞŒp²Dˆ('ü˜o÷;UžŸÂ§ãñ;x¼Q ˜r2#aŒŠ-¹ý¢’­µ©#gVÂ{݉ˆL¿‰0L ƙÒ&!•Í¥$ùüãvôo =šBGR,%) +k‚³£Žç§Ð1ÒR2½1æ] ©Ïà&Ñ)n‚ê\‹ÄOŸôïIáWÚö<>}6TëíÛÍo«œnÛëW3À£^¡Ü±úÏ悷ކX à;'x˜Š…1ŒP:vÉï0;]ﳃ Ë&BDC¼FÊ2FÝ|7÷Åèz¯V??¾,Ͳ8¬Å&$+&S¸M™«ÇŸFÑ~Šžî“ŠQÃã«å¤êò.oo9©íŽ'’pU{ö¬i±ÎÝv´F½+YŠçqf"ÅÜcA¸f´^róÉÈüì]7áq>>>>>endobj +159 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS045×3V072PIÑp VÎO+)O,JUpI-ÎLÏQÉE™%™ùyš!Y\ººP-& 1#C=30ßH!(5-µ(5/9µ$åÂÈ©ï"£endstream +endobj +160 0 obj +118 +endobj +161 0 obj<>>>>>endobj +162 0 obj<>stream +xÚµVMoÛ8½ûW rr€Hþ\;ɞšd»ð¢hÓÔéÉZÙl$Q!©ù÷!%GR·n·ð…"çë=>Îø±7‚!ýF0ÃdQÖ»Zöo/`<„eB'³ù–q7hä&‡O¨Ÿ$îN—_Èn +£‘· ƳÐY^ßß~i RY¡ Æ ˜ƒQ‰Ý `Êu`žÅÌ€Ý + ª@-,‚U´[Ô´ÚJ”Î8F¦r(´Ì­Ì7`…y0—>uT¥Ÿ‡ã—ì«ñlíÚúW"zÀ<6m?*y4!×לP?`ŠÏpM5ˆc½¯ÿ]gϤ-rK¸E„ðN®µÐÏG…x+Sr?®ÌOÑã2E}œ—»>øÜ¡æFs>üL‡á¹SN8‚ö |G4Ë-º2™)f˜[wÿe.#a¥Ê (ÒÈËlM ÒU,“5[ʚ;›4} ƚ‹Dš’wÒn¹‚>>>>>endobj +165 0 obj<>stream +xÚµVQoÛ8 ~ϯ òÔa³;i’8 ·Ý ··íš>u{mzÑbK®$'Ë¿?R²³ÔëÒØ¡EŒH$?ò#ù9÷£¦ô—ÀlÁÿy=z³MÞ]A2‡uI7‹U§°..fqÏÁ¢‘¢z±þJFsH’`¥ º#£õ;ÈD¾EUÐWUXp|Ñ`.K‰|Õ8 *“ic¤rh ×JaîÈ`'ÅÀ¥‹Úhã ÀÌ1BãL?™…$oÿ}҂.½w©M}rÂ§J%F©Ï4Ä»žP¬I)+|­'µº{ž/ã8þü°ÌÈ;Ÿ,-äBA† ԁ*¨3©ŸO¢ªô^ª/]&y.]QÊÇxŸÒÅúTƒÁE&Úâp–ögF8|˜ÖDpƒ.PÌ.À6\»?é¸zˆ}ÂØ£ÀÒÙ!ð(àê ´jëŒzHU à¿†Ú#Ýaˆ‹;T?Aå+^o0ßÉ¿RÅOéæÿTZ=ÒÔukh¸pÄoÙAö;…IšÍâE¿§—`5mŸ;¿§Þäy{ªÐíµÙÂF[­åDØòϦ¹ Q£ÎuÅPkUÈ +‹Ávfø÷:} Ta +ZšÖ¸uF+ù­ëW~a™}ד ç§Dw×,O-p¥h+D¥›_¼J¦Óï/;êæÓxøMá š-Vx€·T-•`Ï}´Î;kfk' ’ °²n*ìo¢J*ÏA)rdîßÞ~¸á§m³Z:ÏÉ$ñÕÉ&÷(,Ú Ñï×Ñ¡^ ¡!]ÊdÅ㴗nøMZÇ­´ºt{ao#¼ç†[“kö%hê¤ïÀu qz:„iœ@Õäg‰¡û>VIËXÆú*EQKE ’ši:¢<ü„ uµö2î[l±ŸE"Ps$ÅSàÙµmÃ`Êõ±Êçêöqwï[jTébžÔù,¹8Fêê$õÙ09'¥ÓRôËâià) Áñ&ž„§D"¥¯Ucžè9ö'́yQà‰òø¬€žmÏdG9gǾ–Þ«Ê‘È/J ŒåøŒÔü±¿´ˆáÆvÜ¿_ÏOٌ‘ê§Ê¨Á`­w”I-¿ÉjÊg¸@“w«.@r¹¤À‹K¿ð¾²›~EþBKÕð#7Ò'È®Qðˆ–é”]|6Ÿq=ÓÇ~;ý½}ýÜÏ[endstream +endobj +166 0 obj +890 +endobj +167 0 obj<>>>>>endobj +168 0 obj<>stream +xÚ­Vßo›0~Ï_q­”°Xh_—þX¤UÊT¦½ôÅÀA݁b“(ÿýÎ6F»¤“¦H Øßïûî󵝿ôñ!Z@°„´š|‰'Ÿî®Á ÎigEÞâì"ðXݯ/ãÚÁ÷Ýþl±ôB³?#¬dUI÷Lãž`-4Ö9Kž.(ôé¶µ,jV)ó°ãƒ=&³„)Ì@i¦¼Ò(ײMÙݾ)€ŽõoaŽ•9å²!j +iɔBz`"ƒ™(ϕKt妆 èéx~à¥?I¬Å äJ+[Û1^²¤Ä®„gÎgâ[…­ò–‡y`ò6Ê1Ak<ýRŒØq +'Vö©I”’W\ÛTWے”6çu)ÜaSˆDï­v§åX8ÉÎiaÓÿ)Äkƒ 5Ъàö¹YgDÎõGÖ\ee)'èˆP`rè$(?Ÿq,†îkY«+Ì9”s W_ °²´¿r«¹Ԝº³Ó’½¹ÎÊÒÏzĊuÆ"-öŸMÒñ\Ò΀Y8÷®œ$!¬~l7ûOjVNr¼Ö¥ éf€‚ԍTŠ +Ž"Å)|ãÍÖú*™(VÐâÃúáv +›Í»á5S”s¤FވÔõ¹QÎZº+AÉ\ï©û§zÒTX ».Ý_ÑÇÍÉZ‚™•¹IL;¨‹Ä j$(=%õ Z³æ¼$’ÔéKZ¤ŽL¡@ +r—Fæ#ªo¼¥FøûúÑhÖ˜³¦ÔËg1od¿«p:ª ƒ–2%÷£Z”펫dK)÷4 +È[tPqZú…mû47®²Ð£àÝ_”ã +©N–˜jóhᎠ+qäJ5صÞkddL3ÈkYQÝ9ækxíi–¡ÃRÚyšX`»þ1^ّxŸUÅ]‡¡‘\9v¤hÒ9i4v¤Jm)–®šc7bÕr…#»AjõË«¶rÿsDԖ~èÆƒ½dí%ƒT¼æ'­¹½&xæbfÑb>ú¯"¼š{×`W#ó~O¾O~T®¹Qendstream +endobj +169 0 obj +792 +endobj +170 0 obj<>>>>>endobj +171 0 obj<>stream +xÚµVÛrÛ6}×Wì£<#Ò¦înŸ_ZuâF‰ä7½@ÀRBJ :ñßw­´ŠÓNÆî圃Å.?÷2¸¢¿ FSÿãeïíºwy ÙÖ9½™Î³tkÑ¥ãt ï˜ÚÕl‡p_+î¤Vöbý‰ƐeÑ!NɎÖ{„¢5Ï[s¨Œ~’uL fHåÐ䌓™6`ЉORí€ë²Ô +~u5+ Dk)˜ f *fœäuÁŒÇ@™³Q„ZhÎ +Ê ¤Ð¥T>š#@\ƒÜ*®…ßÜô1Ý¥ð¸‚7«›Åb‹Õûd>Ÿ\'ÙÐñts%IF£tÚJ2‡ÅÃÝ+åx¨ 'K’ÁÂsVèàÉî¾ò=IÕÕ©dÊ Çb|÷\EB\«'4–L@0ǶÌ"cîD[W•6ޤ’¤y{®Ûg %Qï&=ºAx(Y—pm]t¢ÑûåF—þ¼tm茜¦µ@ë¤bj°>Iïá¦gu›ÂryûJٖ„iō¬,M(¸E6BþSÍ|dÊÀbá[Kzæ{ä…ú‰[^‚¼ÜÙ Â ,¥kB hƒP¹¾(%mšódgð‘´%دãk¢ñ7¼¬3ÈJ :‡›Ç媵óu@u,‚$[-ÀÅáZ‘Zr§àVóº¤óÞ\@mñ”,U‡Ò*éˆ]5b #}Í9ÎÐã«t9Nà>”Ëyb±¤HÁ²*Ð#‰•Ö©i‹æIòæŠ{’)¼)Šƒ#3d͊‚H~‘nO…Ø´K7Iç'Œ˜Ù¾ö—ˆŠ7¨†sz¶Ngðv¿-3ÅJ„$¨–¤¼_w«¿iÓtFte6é˔Tÿ”ï½…… ¨2—+füD›ò¸éq{iÃþ¦ï³îÐüh¦GRþ<Òªý3³VsÉ\+k'Íÿ µ–®hÓ8¿¾¤IøsÞèJRé4çU—[¢F'Æã¶Áϵ4”ñ?k÷¾i1AÛÎp±•¿}iR±ciØÙMO7 ƒ:›~ Ä +ºÉLló:V㯠ó£IH+¥©“UÈ}-‰Aëã ·¬©ãScaSªªv‡–>£û}Àƀ·é n2$úx8ܨûÎmeBqBæÃ(;™`º@Ç®@7r?îÍsÇÁÆQ¤þÛРӉ¸îÏ·äIšÁ¾ÚNWç;VkԊ±Ð\ý}™üöîrçŒÿ‚ѝ1u>õ˜R;ÿnîƒÕ7ÉÛ³©çMÈl2KG0]ù ah¬tî¾ø“i‡Âq’†ƒŒÉl\æ~o4¹¦:¸úÞWàݺ÷¡÷7¤‘66endstream +endobj +172 0 obj +982 +endobj +173 0 obj<>>>>>endobj +174 0 obj<>stream +xڝVÝnÛ< ½ÏSðrf·NÒ¤½Üº¿–¡ù@‘éD›-y’¼.{ú‘úI²´Ÿ; ¹°-‘âáá!•ï“ +.éWÁr +³Ènòf=¹xÕÖ í,®«r +ëúŬ¼*g :±Eo¬píËõW²CUEÛbº(çl»Þ៖Ш–Òèh½‹»¼Šô®½ÛÿV÷ŒkáE?)f³r‘Ì¡wÞônA4É¡•v!ro)ÚÂõ(U£$aê:¡k2´¦ƒÕêm‚EkУmŒíÈ+Á%O¥· Xü> Á­E®f‘§Í<(ÚxWà_0y4{DãÊ8/­ê=åe¶Vt¼¡t‘L½Ùõ£pŽfΎ¨bÆ,&è<6ž+XÝ~ +¼º¡ï '°1~G~­±¼~Ne+䷂֋‡ò˜KçÆY‚ÇŸþYud£GœòÆ©2ã.ӁóËò:Æ]À½Üa=´ÏÓe+P$1h†¶ÝÍ ¥WF‹>®×«‹ª¬Mw«øNZ"l¤+ၴJZtAd™W [áÒ »}5wF¥ÒÁÁí©"] wDëÌ¡rœêúac¨%խ؇5ÔÊ¢$ùí%éqXìL® P+ ±eÎâ&\ …† ‚Ÿë­Ð®µo÷±ó_k$qPŽTyA¤¼üÎXõK0s£œ‹SKè óÏô[t½ÑNmè“Ú BJMG&ÓCsš¯¯~dˆdO‹¬7vPšpðK€–%Û¡®ië,p2 É1±Ü ÆáÁ7唎P“'8ÁŸ(Ÿ¥J“-O¥ÛwgAÓuãø*Ԉ5÷´Ésp“HRFšP‡ùÎ ?°D´¢ñBË —ð³–ÇÎÅúU(×]EӃñ1c ›1½¤žë$ŒêjI’YÜ,£‚ÂÝtoÿÀ'¼E§¶šaƧYRDŸb9½ùó3¿¾,o XÜð÷»õäËä7´Dšendstream +endobj +175 0 obj +900 +endobj +176 0 obj<>>>>>endobj +177 0 obj<>stream +xڍVMs"7½ûWôÑ©†ûº&‰ÚT‘ï]h£ÍŒ4+i ä×çµ$0œ²«€Q¼×ýº5?nF4Ä߈ÆSþ—õÍçÕÍÏ¿>ÐhB« N¦÷£Á­ŠÛñ`:˜Ð£5½mښŸVßa;¡Ñ(ÙöïØ¶«R‘<·¤Úm¥H{rÊ7Öx½ÆÏuø- +m¶àóø²Xv7v¤ZTúŸlÌɑr4NðDÓ8Û8-‚¢BA>¸V†é¢ûNT­òºMTÞÂÉ6>ÁðÊí´„÷Z¦:ÇÙI}02á‚gšÄ&(I¾c^ +N£LL2He}mAŒÚ[ð‰æÚ)¬;Ð2C¼Ú‡âd~b”{e +Ÿ¡J­v8A ãrÔQ0¯N»ÃcAkgE!…ä­üK…}Uµ ݒä8)º¬„÷ÜTQ´ÁrD)ªê@¢(TAÁRÔAmœ­c* £¢S ª´GQQ1£Ü9õÿã,¨¤Î”?fìÑt8¾ÌÔXzTÚ½â#º:@ì×ú€UÝVA7,‡¢€|–"‡é¸Øï)=/WŒó#»á+dáGNý€àCJ)$‘Ò:ÖpuÐË×gž ]$²Ì8r\ô¡TNõ¥@ݵ2ï±m,ˆr²8q`,Ì!FFDn!W•Ú—Z–Tëm Ùè¨Tρeá‰ÎV¬è£D.è#õ`óμ=­V‹úzífô»]_ŸŽï08V¯FlCOz”GSzáZ@÷ÜEgeê)o±XUô¢um±¶¬ó +¬¶‰ ¦Ì¢·^åTþ<—¿Nóž¾Øí}½Ê´J6]²¯mè‘rκ„»Á!»ÄýÄV"ÄùÝ*£°¹ õ!µX–Š~ЊúCèëF ƒ+÷DÐ5÷mˆ ídÉÏ´iòSœòW¶O¢emìˆ Ëÿ9D•wš±ç8¹ÚHó$¨Ã õvùüÛÓKgocÊ·†O_æ]K¯·©{ UaCøóñx{!œm‡ØŽà㘃}ubê^ҍú[‡D3Ò"/é«]9mò˝‰Râšýgë/óÌEçepÀÜ×éîDíÞ弉ø*L‘öN‡¬Ô“ßۚ½Òe“!F#ҝÑ2&§ox©·¸Núd-³5y‡Í…eèìºõáxÒ¯´ák 6B*^ñ퟾]×:Éò¸àš³ŠŸó… /Lá>ƒ}š Æ4FX1êÒnžÇp®XPü!nŽïbýäÑŸÝ Ùe4ä‡ã‡É€_ò.¿Âý²ºùóæ_<™;Lendstream +endobj +178 0 obj +984 +endobj +179 0 obj<>>>>>endobj +180 0 obj<>stream +xÚ­•MoÛ0 †ïù„O-xu>»c·¶X2ÄÝ.½(6¨“%WRZäߏ”â,m{†LB½2~H~dpAŸ c˜Ì¡¨ŸòÁ‡ÛM!¯he~™¥cÈ˳IºH3E?ÏI4…,‹¢ÑxžNY”oñ ÂÔµÐ%xTʁ§Wl±Ü)´àM«Òøfí 2\ƒ…¬d•Ú£ui ô›f4™¤ó–f …ЪNš(é£9¨ŒF ŽÚXŒT~+<ú÷´Ã–2ÀI½é†›@)X+ì¤;húðœ7Í1n$3:ÊbÉíïj6Ô½TQÒ%¬ÿ?T3PM'‘jŽ4n·®¥wÇïJ*t¯÷ZɟQ»œý÷l~° •Plj6†cãÛ*ì^WAOÍoc©¸Q·H+¡àðp¶\^‡f<œ¿‹Ëë´FÙÑj qÃ¾ÃØ³#ÞNç!`cͳ,i˜ù¢0º’›yyFFÇ«BáÉËcIc ´o¢‡:ýLG‚h!bôœŽ5‰ÆØ÷ô‘%Ç6*éü±‰nØö.¦Ž*1Z¤îÒ©(a½ã¹sh»Y.iÓ#Ý,QÒypÿñ-py–ÍøvÍ²“³º2•á^]££ÃÁ_…•a"xó(î-Æz•MSJ,,e;nòÁ·Á/,W%Hendstream +endobj +181 0 obj +664 +endobj +182 0 obj<>>>>>endobj +183 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS045×3V072PIÑp VÎO+)O,JUpI-ÎLÏQÉE™%™ùyš!Y\ººP-†F A#s==@c=3199µ $åÂȼm"endstream +endobj +184 0 obj +117 +endobj +185 0 obj<>>>>>endobj +186 0 obj<>stream +xڝ•ÁrÚ0†ï<Åۃ Ò#q q‚:vfzòâ¨È’+‰Rúô• ¥0S+ÁãíúÛýW¿ÌN=÷ a܇ÁXÙyÈ:wÓ/ÐïA¶v‘ÑxYþi3¡Œ¡zÿ9ûÞ$„ãCB0 +»ý&¥B†º4‡Œ„aá¨AÔm(Ñ!4< …ƒãÓÀTYm-jT[Z`÷œ§WTS!P´S”9—( òŸõœZ +¥ÒöJ'{Å-Pwå¥¿ ¯Ð×½’ìè¾VQn%gÔr% 0WF¢€Ú¢»SPiUhZ_9ƒšÓ©»A“QlƒÖ§ÊµÛ¨’®}¥7-꺗žœ—‚a¯{pE&L+¹÷c’FIâi¤tã`nÃRKeNu‘ÊÖN}"ݽlúqߝ}êž +ô¨Ž^IÚ^*r +êõ%ùDsiëÁ¦{c±ô0ã4º#íИ¤Ë—ÿ4ß@m<äiæáN¹@È4•f5MYŔðОH0›·óžp'ÐڀP¶©iZ½qf`~<’~4‰n`µ»aH«•¸¶ÄóJ<«Õ5ø$ΦíðÆ\î@, .ÑÒ#£fS¥™—KÈØ“Ù®ØÆ$]¾GlN'ÓXê‚Jþ» xØsòØÎž;å§±>R,½¨E²ˆÛY‹­¨_P9§p‚rñ¯wϰ×iÄmó-¶">ÅD›2Í+ûO7šfÁ?ÇtñpˆÞŸG_‹ÿ§ÃñÐ-÷ê@8¨â¬óµó÷¾¬endstream +endobj +187 0 obj +573 +endobj +188 0 obj<>>>>>endobj +189 0 obj<>stream +xÚUÁ‚0 †ï{Šõ0d WQñd‚a>ÁA¦“é ßÞUô`Ú¤Iÿÿû›>ƒÐ.°›É%Y10²…4‘ÅAò¼¨”›”ƒƒ†ºSÛ\—òâÝâë¦>2Dh—…,gùö§:=éÚ@¡éê~h}véìhkf.ûrYp,nNe•mÇgílÕ »Gãô}Ô¶G”²$õM£ã2æxú³XÃÞXÿ…{¡°“äHÞÀ¦G#endstream +endobj +190 0 obj +193 +endobj +191 0 obj<>>>/Annots 59 0 R>>endobj +192 0 obj<>stream +xÚ՛ÛRÜF†ïy +]&YÏùpƒq¨²+Äl`½½§h;äé3‡ÍÌÔ΍W¶«€¦¥é×èï֌ö¯3Ú÷Ÿ6š5\5ËõÙëùÙ«KÛ0ÒÌï*m£´hæ·?ÍWm³½kη›C»9ìž:{3?#3âþ õ_>¼õA£¸œ™fݘƒŸW͍gmÞß7¯.eC©ÿk~7å6u6/â3r݄o?fr³ÜîZbÒÁÝ/f“ÿG_Ñ~ÿÒö_ºö«Ç :³“Q\ZåÔÅc—V»8(ÎŇ?ž+äu±]>®Ý0}™W"P§nL±’¹ßXv:j»RÙÁvãσ;d“•šD{dã&›`ÒºqXÑB6Q>´wmßn–m¨ÂÎôĽ–#ƒVªl±1xÎb¥ÔÑj±‰h˜S¬"BHç^ߌ\’¼·¸’ø‹R² ¬t' f­Ôi/ ¦ºàٜcPXE¸MƒÖ˜9'Ž!ÎU*¤ôûá¡íGÄλ{oö\Á °$vºØ$î>nT»¯`áç笂†[œ#F(F`ɊÙÀ¸h÷ÝýæeP±³;(3! mžñäiúDÆ;áÑ\è Á³.CDtYŽ» ­ôC³$BH¯ËÏíæv›žz/K§™“NX<Ðú.?p¢î!FX Ð 6&Y±³ï}É1 +òëv;O¢|6© L(­ƒÅs A!”6Ѽ¼P  +H T‰‚<ÀV»ÛQ(%B;Ï%…PJÆVÐ Å1¡€D™ïƒ*ä¶[ô‹Õª]yŸŠ‡a2IÜ9žI +™ä ’ÀDeþ†«@¨}Ûw‹ £zÐTˆH\Gg‚B$n;ww"(îq¯BA`û­sôCJOÆÏÕxý.;¹ßL&Çú½ÄqUÔHéuÛnWíӈæ²8,*¤«Ï´óíz½H5Ô8W8±æØ˜¤´(!(Æ$e©0¼bÉV£ ÏR!X†B@&֞!Jqkr%ˆAVŠ[›*CKf"Qbn©Ô[íúR)#s1ˆA¡”I·/Z1‡ºn_Ö È+Pid²Ó ±8®inñc-Žk–*6û•8ÚßlÒ@:{R³)ÏvkdXI“›ûÃ*LEEÑP«J$*|3Z¡ °åj±ß·ûÙò¾ ~>ý0‘\uü<…HîD u) ùég^£ °OۏƒBœM¤Ãdâ¬0ó2qžÌœã&$G…‚<Àv}·9´}L§Ÿ ҈KQü7zI +—b$J$0J˜„¬(19ß0Á™@4´^)æ#éÊ«|·X¶#3ýÁO˜êclïºý¢‚á-NxͰAMd~¾ˆA1¨‰JUEà $*•{¾¨PØùvó¥Ýt~ŽDnñ¤3mÐËÇÍÒÏM§y¨ïÚC#3ËrŠA֘YžŠ@ý5‘(Ó·Ôx€ý6Ÿ_e]Õ~>º‚¹ 2ëHڍeLcms ‹A¡±!©† Ԝ‰R_½*TÌ'ØÕõ˜ÄÅÞþž0LJ$ØñøUÓµ ¦T®ƒ1(¤V:ÕAÎÜ$ÌÝË +ò{·ØÜ?.îÇü¢@8 Qî:WÀ´O¯·AT–šçbƒB=¬ºK´ýL$^Æ©PhÔ«ƒ÷'O:”,"‘*ÖÙcPH¤†uv‰¶‰W²*ä¶Û§14¡•,L&Q¬²Ç I «ìíü‰º&BÖ(ÈÌ˔‡Ñɞðþ‡F¼X`A¡—Ù³±Ö-‘¨ðë% +ò‹ú¶;°¤Ó¯®`"±by=…HlkºÇÏéªù€:´†¢6•];Þ0Q¢ó’J rÃDɰ¸®†)q¬:æ@Ú¤<´·«tŸMñe)dPY‘=܊ÊÂí°È®ÐV 0~ÕVœ˜Ò¯‡‡mßý“_:%']G´1Ū¸©ÅͰ&®Ð 0þ‰ºæÄ,Îã*Ór·}T±®ê¥p5¬„+´A $QÇëà‰t¾êÚM|‰ELçÑQHkà²^—ý…uGñS޲¢Ä,¼p²¹ëîûòÎ:Q‚½oR¼Eë7 †eo…¿1Ô}×'ftÑõíÒõCOcsÁOÿ:Uƒ4ðnüËÅði†ð`øÝUÆäeÅ93G‹ÙÓÑY0X§~™ÿ¬LÀǾ®¯§÷FgT(Ÿ>KhàÝi×>>>/Annots 76 0 R>>endobj +195 0 obj<>stream +xÚ՘Ïo›0€ïù+|Ü¥þ‰áØuk¥i“¶%۝QÈiê¿gûLµÆ»…¶U¢'㏾/æù9¿7ŒPøeD¤æ¯l6v›ë»œpJv„©œ¤Z’ÝþÝ®x8V¤{$·];Ví8¼ß=m>í64¡@0/̼ü¸'š'”¤B%iHžÂ› Ždkè/&ôr}' cæ~šÃµfÜP$i¢É«w À ÌN±¼ Ž#ìs÷`ÿa–C¶'ÿa4"ó$Ú33’8Øñ’²˜$$1!'îB’‡}釺=˜T—7uDóDNŽl8b4‘ÞQs„$ÆéÄ]8ò°¯EÝg°8×±”b–dÀMn”û‹fM*×£&F_÷N7‹)…²€ù ÷­¯¡Pôö±^ÚÖO xʼ6Dq“™ 03¨Œ*õt¦$’é$]RpØr¶ÏÃX5¯£‚Ù°¼3(n [Ô¯3K{žŸ˜Ì^æ…ãsÛ5MÑîíÇ%õ…wtI§ù¼»¸ XњúD',òà{ãò%ʍ{XQ–Õi´¾kkxô‹XR鼅¸ °¤´ßḆ„$´¢paeіÕñmY’bÞD\X’Òo"&Ÿˆ%$1È=_¢paûz0ݔ­Œt ’¢ŽµUߥaƒÀ‘`~ѐ_Ä’7Æ…ã«Z¯èí¬$¦]½¶‰Ø °Ä¦š¤bŽÃ¨2õ9á¸EO“­¥¡ý/CTuہ!*纝Æ!‰ÙÖbÂq„Ožq=ÛJšÚˆ#™Ó¹j»`v$s6WíØéȓLS›.Q8ްãi‹qmmm̓ÖsÝvAàIgsݎ<‰qS{(GX_=U¥÷”­ß“9ËHۘÀ'ëÌíúNá±Û\e‹î͹öšo[d±„ᰥܻa(úgûÌå [S…ú§Aqþ` …¶µFIØÖ]0)ôß\ÀAŠÌ•œ›s]gC‚˜ðþà†‘´«úfÀ=0[£Æ¨:hÓI æ3•„ uÂxLr5íø„ãUö]ûì¤A»%Ö%Íéšs¤Ó7`®#•Áâá96Š·?¿mɶ{ÿ}E>VC}hÍ[Ù×§±îì®vŔi®4·©Ö5šü¾ù hòeendstream +endobj +196 0 obj +868 +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<>1<>2<>4<>]>>>>endobj +xref +0 261 +0000000000 65535 f +0000000015 00000 n +0000000225 00000 n +0000001791 00000 n +0000001865 00000 n +0000001947 00000 n +0000002025 00000 n +0000002102 00000 n +0000002181 00000 n +0000002257 00000 n +0000002338 00000 n +0000002397 00000 n +0000002449 00000 n +0000002534 00000 n +0000002558 00000 n +0000002662 00000 n +0000002767 00000 n +0000002872 00000 n +0000002977 00000 n +0000003081 00000 n +0000003186 00000 n +0000003291 00000 n +0000003395 00000 n +0000003500 00000 n +0000003605 00000 n +0000003710 00000 n +0000003815 00000 n +0000003920 00000 n +0000004025 00000 n +0000004130 00000 n +0000004235 00000 n +0000004340 00000 n +0000004445 00000 n +0000004550 00000 n +0000004655 00000 n +0000004760 00000 n +0000004865 00000 n +0000004970 00000 n +0000005075 00000 n +0000005180 00000 n +0000005285 00000 n +0000005390 00000 n +0000005495 00000 n +0000005600 00000 n +0000005705 00000 n +0000005810 00000 n +0000005915 00000 n +0000006020 00000 n +0000006125 00000 n +0000006230 00000 n +0000006335 00000 n +0000006440 00000 n +0000006545 00000 n +0000006650 00000 n +0000006755 00000 n +0000006860 00000 n +0000006965 00000 n +0000007069 00000 n +0000007172 00000 n +0000007275 00000 n +0000007607 00000 n +0000007712 00000 n +0000007817 00000 n +0000007922 00000 n +0000008027 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 +0000009074 00000 n +0000009178 00000 n +0000009282 00000 n +0000009411 00000 n +0000009443 00000 n +0000009475 00000 n +0000010334 00000 n +0000010382 00000 n +0000010430 00000 n +0000010478 00000 n +0000010526 00000 n +0000010574 00000 n +0000010622 00000 n +0000010670 00000 n +0000010718 00000 n +0000010766 00000 n +0000010814 00000 n +0000010862 00000 n +0000010910 00000 n +0000010958 00000 n +0000011006 00000 n +0000011054 00000 n +0000011102 00000 n +0000011150 00000 n +0000011198 00000 n +0000011246 00000 n +0000011294 00000 n +0000011343 00000 n +0000011392 00000 n +0000011441 00000 n +0000011490 00000 n +0000011539 00000 n +0000011588 00000 n +0000011637 00000 n +0000011686 00000 n +0000011735 00000 n +0000011784 00000 n +0000011833 00000 n +0000011882 00000 n +0000011931 00000 n +0000011980 00000 n +0000012029 00000 n +0000012078 00000 n +0000012127 00000 n +0000012176 00000 n +0000012225 00000 n +0000012274 00000 n +0000012323 00000 n +0000012372 00000 n +0000012421 00000 n +0000012470 00000 n +0000012519 00000 n +0000012568 00000 n +0000012617 00000 n +0000012666 00000 n +0000012715 00000 n +0000012764 00000 n +0000012813 00000 n +0000012862 00000 n +0000012911 00000 n +0000012960 00000 n +0000013009 00000 n +0000013058 00000 n +0000013107 00000 n +0000013156 00000 n +0000013205 00000 n +0000013254 00000 n +0000013303 00000 n +0000013352 00000 n +0000013565 00000 n +0000013717 00000 n +0000020067 00000 n +0000020089 00000 n +0000020184 00000 n +0000020286 00000 n +0000020306 00000 n +0000020461 00000 n +0000021432 00000 n +0000021453 00000 n +0000021566 00000 n +0000021750 00000 n +0000021771 00000 n +0000021912 00000 n +0000022676 00000 n +0000022697 00000 n +0000022810 00000 n +0000022999 00000 n +0000023020 00000 n +0000023170 00000 n +0000024179 00000 n +0000024200 00000 n +0000024359 00000 n +0000025320 00000 n +0000025341 00000 n +0000025472 00000 n +0000026335 00000 n +0000026356 00000 n +0000026497 00000 n +0000027550 00000 n +0000027571 00000 n +0000027702 00000 n +0000028673 00000 n +0000028694 00000 n +0000028834 00000 n +0000029889 00000 n +0000029910 00000 n +0000030041 00000 n +0000030776 00000 n +0000030797 00000 n +0000030910 00000 n +0000031098 00000 n +0000031119 00000 n +0000031259 00000 n +0000031903 00000 n +0000031924 00000 n +0000032055 00000 n +0000032319 00000 n +0000032340 00000 n +0000032494 00000 n +0000034699 00000 n +0000034721 00000 n +0000034875 00000 n +0000035814 00000 n +0000035835 00000 n +0000035890 00000 n +0000035995 00000 n +0000036139 00000 n +0000036245 00000 n +0000036365 00000 n +0000036474 00000 n +0000036623 00000 n +0000036733 00000 n +0000036840 00000 n +0000036994 00000 n +0000037130 00000 n +0000037227 00000 n +0000037337 00000 n +0000037452 00000 n +0000037565 00000 n +0000037665 00000 n +0000037823 00000 n +0000037920 00000 n +0000038030 00000 n +0000038128 00000 n +0000038272 00000 n +0000038377 00000 n +0000038492 00000 n +0000038598 00000 n +0000038761 00000 n +0000038876 00000 n +0000038997 00000 n +0000039117 00000 n +0000039242 00000 n +0000039363 00000 n +0000039483 00000 n +0000039593 00000 n +0000039741 00000 n +0000039843 00000 n +0000039959 00000 n +0000040079 00000 n +0000040192 00000 n +0000040309 00000 n +0000040426 00000 n +0000040528 00000 n +0000040679 00000 n +0000040786 00000 n +0000040900 00000 n +0000041013 00000 n +0000041133 00000 n +0000041258 00000 n +0000041368 00000 n +0000041479 00000 n +0000041593 00000 n +0000041704 00000 n +0000041807 00000 n +0000041952 00000 n +0000042052 00000 n +0000042165 00000 n +0000042279 00000 n +0000042392 00000 n +0000042501 00000 n +0000042615 00000 n +0000042728 00000 n +0000042828 00000 n +0000042962 00000 n +0000043059 00000 n +0000043159 00000 n +trailer +<> +startxref +43386 +%%EOF diff --git a/doc/sdd.shtml b/doc/sdd.shtml new file mode 100644 index 0000000000..2ef7a7320b --- /dev/null +++ b/doc/sdd.shtml @@ -0,0 +1,435 @@ + + + + + + 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.1. + + + +

Document Overview

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

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

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

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: + +
    + +
  • quit - Quits the lpc command. + +
  • status - Shows the status of printers and jobs in the queue. + +
+ +

lpr

+ +The lpr command submits a job for printing. The CUPS version of lpr silently +ignores the "i", "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.cgi

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

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

+ +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, get a list of available +classes, get the default printer or class, get the default server name, get +the local username, and get a password string. + +

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

imagetoraster

+ +The imagetoraster filter converts image files into CUPS raster data. + +

pstops

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

pstoraster

+ +The pstoraster filter converts PostScript program data into CUPS raster data. + +

rastertohp

+ +The rastertohp filter handles converting CUPS raster data to HP PCL and +supports both color and black-and-white printers. + +

texttops

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

Scheduler

+ +The scheduler is a fully-functional HTTP/1.1 and IPP/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. + +

Logging

+ +The logging module manages the access, error, and page log files that are +generated by the scheduler. + +

Main

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

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 printers and 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), "F" (filter), and "E" (enable and accept) 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. + + + + + diff --git a/doc/spm.html b/doc/spm.html new file mode 100644 index 0000000000..0b46081c5f --- /dev/null +++ b/doc/spm.html @@ -0,0 +1,3706 @@ + + + +DRAFT - CUPS Software Programmers Manual + + + + + + + +

+

DRAFT - CUPS Software Programmers Manual


+CUPS-SPM-1.1
+Easy Software Products
+Copyright 1997-2000, All Rights Reserved
+
+
+

Table of Contents

+
+
Preface + +1 - Printing System Overview + +2 - The CUPS API + +3 - Writing Filters + +4 - Writing Printer Drivers + +5 - Writing Backends + +A - Constants + +B - Structures + +C - Functions + +
+

Preface

+ This software programmers manual provides software programming +information for the Common UNIX Printing System ("CUPS") Version 1.1. +

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 5.50) and an image file RIP that +is used to support non-PostScript printers.

+

Document Overview

+

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

+
    +
  • 1 - Printing System Overview
  • +
  • 2 - The CUPS API
  • +
  • 3 - Writing Filters
  • +
  • 4 - Writing Printer Drivers
  • +
  • 5 - Writing Backends
  • +
  • A - Constants
  • +
  • B - Structures
  • +
  • C - Functions
  • +
+

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 - The CUPS API

+

This chapter describes the CUPS Application Programmers Interface +("API").

+

The CUPS Library

+

Detecting the CUPS Library in Autoconf

+

Basic Services

+

Include Files

+

Getting the Available Printers and Classes

+

Printing Files

+

Setting Printer Options

+

Cancelling Jobs

+

HTTP Services

+

Include Files

+

Connecting to a Server

+

Setting Request Fields

+

Issuing a Request

+

Getting the Request Status

+

Sending Request Data

+

Reading Request Data

+

IPP Services

+

Include Files

+

Creating an IPP Request

+

Adding Attributes

+

Sending an IPP Request

+

Reading an IPP Response

+

Finding Attributes

+

Looping Through Attributes

+

IPP Standard Operations

+

IPP Extension Operations

+

CUPS Extension Operations

+

Language Services

+

Include Files

+

Getting the Default Language

+

Getting the Language Encoding

+

Getting a Language String

+

PPD Services

+

Include Files

+

Loading a PPD File

+

Options and Groups

+

Finding an Option

+

Finding a Page Size

+

Marking Options

+

Checking for Conflicts

+

Sending Options

+

3 - Writing Filters

+

This chapter describes how to write a file filter for CUPS.

+

Overview

+

Security Considerations

+ Users and Groups +

Temporary Files

+

Page Accounting

+

Command-Line Arguments

+

Copy Generation

+

Environment Variables

+

Writing a HTML Filter

+

4 - Writing Printer Drivers

+

This chapter discusses how to write a printer driver, which is a +special filter program that converts CUPS raster data into the +appropriate commands and data required for a printer.

+

Overview

+

Page Accounting

+

Color Management

+

Raster Functions

+

cupsRasterOpen()

+

cupsRasterReadHeader()

+

cupsRasterReadPixels()

+

cupsRasterClose()

+

Writing a HP-PCL Driver

+

5 - Writing Backends

+

This chapter describes how to write a backend for CUPS. Backends +communicate directly with printers and allow printer drivers and +filters to send data using any type of connection transparently.

+

Overview

+

Security Considerations

+ Users and Groups +

Temporary Files

+

Page Accounting

+

Retries

+

Command-Line Arguments

+

Copy Generation

+

Environment Variables

+

Writing a Serial Port Backend

+

A - Constants

+

This appendix lists all of the constants that are defined by the +CUPS API.

+

CUPS Constants

+

HTTP Constants

+

IPP Constants

+

Language Constants

+

PPD Constants

+

Raster Constants

+

B - Structures

+

This appendix describes all of the structures that are defined by +the CUPS API.

+

+

C - Functions

+

This appendix provides a reference for all of the CUPS API +functions. + +

+

cupsAddOption()

+

Usage

+
+int
+cupsAddOption(const char *name,
+              const char *value,
+              int num_options,
+	      cups_option_t **options);
+
+

Arguments

+
+ + + + + + + +
ArgumentDescription
nameThe name of the option.
valueThe value of the option.
num_optionsNumber of options currently in the array.
optionsPointer to the options array.
+
+

Returns

+

The new number of options.

+

Description

+

cupsAddOption() adds an option to the specified array.

+

Example

+
+#include <cups.h>
+
+...
+
+/* Declare the options array */
+int           num_options;
+cups_option_t *options;
+
+/* Initialize the options array */
+num_options = 0;
+options     = (cups_option_t *)0;
+
+/* Add options using cupsAddOption() */
+num_options = cupsAddOption("media", "letter", num_options, &options);
+num_options = cupsAddOption("resolution", "300dpi", num_options, &options);
+
+

See Also

+cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + + +

cupsCancelJob()

+

Usage

+
+int
+cupsCancelJob(const char *dest,
+              int job);
+
+

Arguments

+
+ + + + +
ArgumentDescription
destPrinter or class name
jobJob ID
+
+

Returns

+

1 on success, 0 on failure. On failure the error can be found by +calling cupsLastError().

+

Description

+

cupsCancelJob() cancels the specifies job.

+

Example

+
+#include <cups.h>
+
+cupsCancelJob("LaserJet", 1);
+
+

See Also

+

cupsLastError(), +cupsPrintFile() + +

+

cupsDoFileRequest()

+

Usage

+
+ipp_t *
+cupsDoFileRequest(http_t *http,
+                  ipp_t *request,
+                  const char *resource,
+		  const char *filename);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
filenameFile to send with POST request (NULL + pointer if none.)
+
+

Returns

+

IPP response data or NULL if the request fails. On +failure the error can be found by calling +cupsLastError().

+

Description

+

cupsDoFileRequest() does a HTTP POST request and +provides the IPP request and optionally the contents of a file to the +IPP server. It also handles resubmitting the request and performing +password authentication as needed.

+

Example

+
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_PRINT_FILE;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+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, "ipp://hostname/resource");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+             NULL, cupsUser());
+
+/* Do the request... */
+response = cupsDoFileRequest(http, request, "/resource", "filename.txt");
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), httpConnect() +, ippAddString(), +ippNew() + +

+

cupsDoRequest()

+

Usage

+
+ipp_t *
+cupsDoRequest(http_t *http,
+              ipp_t *request,
+              const char *resource);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
+
+

Returns

+

IPP response data or NULL if the request fails. On +failure the error can be found by calling +cupsLastError().

+

Description

+

cupsDoRequest() does a HTTP POST request and provides +the IPP request to the IPP server. It also handles resubmitting the +request and performing password authentication as needed.

+

Example

+
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+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, "ipp://hostname/resource");
+
+/* Do the request... */
+response = cupsDoRequest(http, request, "/resource");
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), httpConnect() +, ippAddString(), +ippNew() + +

+

cupsFreeOptions()

+

Usage

+
+void
+cupsFreeOptions(int num_options,
+                cups_option_t *options);
+
+
+

Arguments

+
+ + + + +
ArgumentDescription
num_optionsNumber of options in array.
optionsPointer to options array.
+
+

Description

+

cupsFreeOptions() frees all memory associated with the +option array specified.

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+
+

See Also

+

cupsAddOption(), +cupsGetOption(), cupsMarkOptions(), cupsParseOptions() + +

+

cupsGetClasses()

+

Usage

+
+int
+cupsGetClasses(char ***classes);
+
+

Arguments

+
+ + + +
ArgumentDescription
classesPointer to character pointer array.
+
+

Returns

+

The number of printer classes available.

+

Description

+

cupsGetClasses() gets a list of the available printer +classes. The returned array should be freed using the free() + when it is no longer needed.

+

Example

+
+#include <cups/cups.h>
+
+int  i;
+int  num_classes;
+char **classes;
+
+...
+
+num_classes = cupsGetClasses(;
+
+...
+
+if (num_classes > 0)
+{
+  for (i = 0; i num_classes; i ++)
+    free(classes[i]);
+
+  free(classes);
+}
+
+

See Also

+

cupsGetDefault(), +cupsGetPrinters() + +

+

cupsGetDefault()

+

Usage

+
+const char *
+cupsGetDefault(void);
+
+

Returns

+

A pointer to the default destination.

+

Description

+

cupsGetDefault() gets the default destination printer +or class. The default destination is stored in a static string and will +be overwritten (usually with the same value) after each call.

+

Example

+
+#include <cups/cups.h>
+
+printf("The default destination is %s\n", cupsGetDefault());
+
+

See Also

+

cupsGetClasses(), +cupsGetPrinters() + +

+

cupsGetOption()

+

Usage

+
+const char *
+cupsGetOption(const char *name,
+              int num_options,
+              cups_option_t *options);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
nameThe name of the option.
num_optionsThe number of options in the array.
optionsThe options array.
+
+

Returns

+

A pointer to the option values or NULL if the option is +not defined.

+

Description

+

cupsGetOption() returns the first occurrence of the +named option. If the option is not included in the options array then a +NULL pointer is returned.

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+const char    *media;
+
+...
+
+media = cupsGetOption("media", num_options, options);
+
+

See Also

+

cupsAddOption(), +cupsFreeOptions(), cupsMarkOptions() +, cupsParseOptions() + +

+

cupsGetPassword()

+

Usage

+
+const char *
+cupsGetPassword(const char *prompt);
+
+

Arguments

+
+ + + +
ArgumentDescription
promptThe prompt to display to the user.
+
+

Returns

+

A pointer to the password that was entered or NULL if +no password was entered.

+

Description

+

cupsGetPassword() displays the prompt string and asks +the user for a password. The password text is not echoed to the user.

+

Example

+
+#include <cups/cups.h>
+
+char *password;
+
+...
+
+password = cupsGetPassword("Please enter a password:");
+
+

See Also

+

cupsServer(), +cupsUser() + +

+

cupsGetPPD()

+

Usage

+
+const char *
+cupsGetPPD(const char *printer);
+
+

Arguments

+
+ + + +
ArgumentDescription
printerThe name of the printer.
+
+

Returns

+

The name of a temporary file containing the PPD file or NULL + if the printer cannot be located or does not have a PPD file.

+

Description

+

cupsGetPPD() gets a copy of the PPD file for the named +printer. The printer name can be of the form "printer" or +"printer@hostname".

+

You should remove (unlink) the PPD file after you are done using it. +The filename is stored in a static buffer and will be overwritten with +each call to cupsGetPPD().

+

Example

+
+#include <cups/cups.h>
+
+char *ppd;
+
+...
+
+ppd = cupsGetPPD("printer@hostname");
+
+...
+
+unlink(ppd);
+
+ + +

cupsGetPrinters()

+

Usage

+
+int
+cupsGetPrinters(char ***printers);
+
+

Arguments

+
+ + + +
ArgumentDescription
printersPointer to character pointer array.
+
+

Returns

+

The number of printer printers available.

+

Description

+

cupsGetPrinters() gets a list of the available +printers. The returned array should be freed using the free() + when it is no longer needed.

+

Example

+
+#include <cups/cups.h>
+
+int  i;
+int  num_printers;
+char **printers;
+
+...
+
+num_printers = cupsGetPrinters(;
+
+...
+
+if (num_printers > 0)
+{
+  for (i = 0; i num_printers; i ++)
+    free(printers[i]);
+
+  free(printers);
+}
+
+

See Also

+

cupsGetClasses(), +cupsGetDefault() + +

+

cupsLangDefault()

+

Usage

+
+const char *
+cupsLangDefault(void);
+
+

Returns

+

A pointer to the default language structure.

+

Description

+

cupsLangDefault() returns a language structure for the +default language. The default language is defined by the LANG + environment variable. If the specified language cannot be located then +the POSIX (English) locale is used.

+

Call cupsLangFree() to free any memory associated with +the language structure when you are done.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+language = cupsLangDefault();
+
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangEncoding(), +cupsLangFlush(), cupsLangFree(), +cupsLangGet(), cupsLangString() + +

+

cupsLangEncoding()

+

Usage

+
+char *
+cupsLangEncoding(cups_lang_t *language);
+
+

Arguments

+
+ + + +
ArgumentDescription
languageThe language structure.
+
+

Returns

+

A pointer to the encoding string.

+

Description

+

cupsLangEncoding() returns the language encoding used +for the specified language, e.g. "iso-8859-1", "utf-8", etc.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *encoding;
+...
+
+language = cupsLangDefault();
+encoding = cupsLangEncoding(language);
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangFlush(), cupsLangFree(), +cupsLangGet(), cupsLangString() + +

+

cupsLangFlush()

+

Usage

+
+void
+cupsLangFlush(void);
+
+

Description

+

cupsLangFlush() frees all language structures that have +been allocated.

+

Example

+
+#include <cups/language.h>
+
+...
+
+cupsLangFlush();
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFree(), +cupsLangGet(), cupsLangString() + +

+

cupsLangFree()

+

Usage

+
+void
+cupsLangFree(cups_lang_t *language);
+
+

Arguments

+
+ + + +
ArgumentDescription
languageThe language structure to free.
+
+

Description

+

cupsLangFree() frees the specified language structure.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFlush(), +cupsLangGet(), cupsLangString() + +

+

cupsLangGet()

+

Usage

+
+cups_lang_t *
+cupsLangGet(const char *name);
+
+

Arguments

+
+ + + +
ArgumentDescription
nameThe name of the locale.
+
+

Returns

+

A pointer to a language structure.

+

Description

+

cupsLangGet() returns a language structure for the +specified locale. If the locale is not defined then the POSIX (English) +locale is substituted.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+
+...
+
+language = cupsLangGet("fr");
+
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFlush(), +cupsLangFree(), cupsLangString() + +

+

cupsLangString()

+

Usage

+
+char *
+cupsLangString(cups_lang_t *language,
+               int         message);
+
+

Arguments

+
+ + + + +
ArgumentDescription
languageThe language to query.
messageThe message number.
+
+

Returns

+

A pointer to the message string or NULL if the message +is not defined.

+

Description

+

cupsLangString() returns a pointer to the specified +message string in the specified language.

+

Example

+
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *s;
+...
+
+language = cupsLangGet("fr");
+
+s = cupsLangString(language, CUPS_MSG_YES);
+
+...
+
+cupsLangFree(language);
+
+

See Also

+

cupsLangDefault(), +cupsLangEncoding(), cupsLangFlush(), +cupsLangFree(), cupsLangGet() + +

+

cupsLastError()

+

Usage

+
+ipp_status_t
+cupsLastError(void);
+
+

Returns

+

An enumeration containing the last IPP error.

+

Description

+

cupsLastError() returns the last IPP error that +occurred. If no error occurred then it will return IPP_OK + or IPP_OK_CONFLICT.

+

Example

+
+#include <cups/cups.h>
+
+ipp_status_t status;
+
+...
+
+status = cupsLastError();
+
+

See Also

+

cupsCancelJob(), +cupsPrintFile() + +

+

cupsMarkOptions()

+

Usage

+
+int
+cupsMarkOptions(ppd_file_t *ppd,
+                int num_options,
+                cups_option_t *options);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
ppdThe PPD file to mark.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+
+

Returns

+

The number of conflicts found.

+

Description

+

cupsMarkOptions() marks options in the PPD file. It +also handles mapping of IPP option names and values to PPD option +names.

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+ppd_file_t    *ppd;
+
+...
+
+cupsMarkOptions(ppd, num_options, options);
+
+

See Also

+

cupsAddOption(), +cupsFreeOptions(), cupsGetOption(), +cupsParseOptions() + +

+

cupsParseOptions()

+

Usage

+
+int
+cupsParseOptions(const char *arg,
+                 int num_options,
+                 cups_option_t **options);
+
+

Arguments

+
+ + + + + + +
ArgumentDescription
argThe string containing one or more options.
num_optionsThe number of options in the options array.
optionsA pointer to the options array pointer.
+
+

Returns

+

The new number of options in the array.

+

Description

+

cupsParseOptions() parses the specifies string for one +or more options of the form "name=value", "name", or "noname". It can +be called multiple times to combine the options from several strings.

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options     = (cups_option_t *)0;
+num_options = cupsParseOptions(argv[5], num_options, &options);
+
+

See Also

+

cupsAddOption(), +cupsFreeOptions(), cupsGetOption(), +cupsMarkOptions() + +

+

cupsPrintFile()

+

Usage

+
+int
+cupsPrintFile(const char *printer,
+              const char *filename,
+              const char *title,
+	      int num_options,
+	      cups_option_t *options);
+
+

Arguments

+
+ + + + + + + + +
ArgumentDescription
printerThe printer or class to print to.
filenameThe file to print.
titleThe job title.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+
+

Returns

+

The new job ID number or 0 on error.

+

Description

+

cupsPrintFile() sends a file to the specified printer +or class for printing. If the job cannot be printed the error code can +be found by calling cupsLastError().

+

Example

+
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+cupsPrintFile("printer@hostname", "filename.ps", "Job Title", num_options,
+              options);
+
+

See Also

+

cupsCancelJob(), +cupsLastError() + +

+

cupsRasterClose()

+

Usage

+
+void
+cupsRasterClose(cups_raster_t *ras);
+
+

Arguments

+
+ + + +
ArgumentDescription
rasThe raster stream to close.
+
+

Description

+

cupsRasterClose() closes the specified raster stream.

+

Example

+
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+cupsRasterClose(ras);
+
+

See Also

+

cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterOpen()

+

Usage

+
+cups_raster_t *
+cupsRasterOpen(int fd,
+               cups_mode_t mode);
+
+

Arguments

+
+ + + + +
ArgumentDescription
fdThe file descriptor to use.
modeThe mode to use; CUPS_RASTER_READ or +CUPS_RASTER_WRITE.
+
+

Returns

+

A pointer to a raster stream or NULL if there was an +error.

+

Description

+

cupsRasterOpen() opens a raster stream for reading or +writing.

+

Example

+
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+ras = cupsRasterOpen(0, CUPS_RASTER_READ);
+
+

See Also

+

cupsRasterClose(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterReadHeader()

+

Usage

+
+unsigned
+cupsRasterReadHeader(cups_raster_t *ras,
+                     cups_page_header_t *header);
+
+

Arguments

+
+ + + + +
ArgumentDescription
rasThe raster stream to read from.
headerA pointer to a page header structure to read +into.
+
+

Returns

+

1 on success, 0 on EOF or error.

+

Description

+

cupsRasterReadHeader() reads a page header from the +specified raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterReadPixels()

+

Usage

+
+unsigned
+cupsRasterReadPixels(cups_raster_t *ras,
+                     unsigned char *pixels,
+		     unsigned length);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
rasThe raster stream to read from.
pixelsThe pointer to a pixel buffer.
lengthThe number of bytes of pixel data to read.
+
+

Returns

+

The number of bytes read or 0 on EOF or error.

+

Description

+

cupsRasterReadPixels() reads pixel data from the +specified raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

+

cupsRasterWriteHeader()

+

Usage

+
+unsigned
+cupsRasterWriteHeader(cups_raster_t *ras,
+                      cups_page_header_t *header);
+
+

Arguments

+
+ + + + +
ArgumentDescription
rasThe raster stream to write to.
headerA pointer to the page header to write.
+
+

Returns

+

1 on success, 0 on error.

+

Description

+

cupsRasterWriteHeader() writes the specified page +header to a raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWritePixels() + +

+

cupsRasterWritePixels()

+

Usage

+
+unsigned
+cupsRasterWritePixels(cups_raster_t *ras,
+                      unsigned char *pixels,
+		      unsigned length);
+
+

Arguments

+
+ + + + + +
ArgumentDescription
rasThe raster stream to write to.
pixelsThe pixel data to write.
lengthThe number of bytes to write.
+
+

Returns

+

The number of bytes written.

+

Description

+

cupsRasterWritePixels() writes the specified pixel data +to a raster stream.

+

Example

+
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+

See Also

+

cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader() + +

+

cupsServer()

+

Usage

+
+const char *
+cupsServer(void);
+
+

Returns

+

A pointer to the default server name.

+

Description

+

cupsServer() returns a pointer to the default server +name. The server name is stored in a static location and will be +overwritten with every call to cupsServer()

+

The default server is determined from the following locations:

+
    +
  1. The CUPS_SERVER environment variable,
  2. +
  3. The ServerName directive in the cupsd.conf + file,
  4. +
  5. The default host, "localhost".
  6. +
+

Example

+
+#include <cups/cups.h>
+
+const char *server;
+
+server = cupsServer();
+
+

See Also

+

cupsGetPassword(), +cupsUser() + +

+

cupsTempFile()

+

Usage

+
+char *
+cupsTempFile(char *filename,
+             int length);
+
+

Arguments

+
+ + + + +
ArgumentDescription
filenameThe character string to hold the temporary +filename.
lengthThe size of the filename string in bytes.
+
+

Returns

+

A pointer to filename.

+

Description

+

cupsTempFile() generates a temporary filename for the +/var/tmp directory or the directory specified by the TMPDIR + environment variable.

+

Example

+
+#include <cups/cups.h>
+
+char filename[256];
+
+cupsTempFile(filename, sizeof(filename));
+
+ + +

cupsUser()

+

Usage

+
+const char *
+cupsUser(void);
+
+

Returns

+

A pointer to the current username or NULL if the user +ID is undefined.

+

Description

+

cupsUser() returns the name associated with the current +user ID as reported by the getuid() system call.

+

Example

+
+#include <cups/cups.h>
+
+const char *user;
+
+user = cupsUser();
+
+

See Also

+

cupsGetPassword(), +cupsServer() + +

+

httpBlocking()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpCheck()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpClearFields()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpClose()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpConnect()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpDecode64()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpDelete()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpEncode64()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpError()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpFlush()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpGet()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpGets()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpGetDateString()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpGetDateTime()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpGetField()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpGetLength()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpHead()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpInitialize()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpOptions()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpPost()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpPrintf()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpPut()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpRead()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpReconnect()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpSeparate()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpSetField()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpTrace()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpUpdate()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

httpWrite()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddBoolean()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddBooleans()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddDate()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddInteger()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddIntegers()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddRange()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddRanges()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddResolution()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddResolutions()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddSeparator()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddString()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippAddStrings()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippDateToTime()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippDelete()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippFindAttribute()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippLength()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippNew()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippPort()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippRead()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippTimeToDate()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ippWrite()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdClose()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdConflicts()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

pddEmitFd()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdEmit()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdFindChoice()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdFindMarkedChoice()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdFindOption()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdIsMarked()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdMarkDefaults()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdMarkOption()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdOpenFd()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdOpenFile()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdOpen()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdPageLength()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdPageSize()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + +

ppdPageWidth()

+

Usage

+
+
+

Arguments

+
+ + + +
ArgumentDescription
+
+

Returns

+

Description

+

Example

+
+
+

See Also

+ + diff --git a/doc/spm.pdf b/doc/spm.pdf new file mode 100644 index 0000000000..c9d5bb5793 --- /dev/null +++ b/doc/spm.pdf @@ -0,0 +1,7653 @@ +%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[12 0 R +]endobj +14 0 obj<>endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj[14 0 R +15 0 R +16 0 R +]endobj +18 0 obj<>endobj +19 0 obj<>endobj +20 0 obj<>endobj +21 0 obj[18 0 R +19 0 R +20 0 R +]endobj +22 0 obj<>endobj +23 0 obj<>endobj +24 0 obj<>endobj +25 0 obj[22 0 R +23 0 R +24 0 R +]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[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 +]endobj +36 0 obj<>endobj +37 0 obj<>endobj +38 0 obj<>endobj +39 0 obj<>endobj +40 0 obj[36 0 R +37 0 R +38 0 R +39 0 R +]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[41 0 R +42 0 R +43 0 R +44 0 R +45 0 R +46 0 R +47 0 R +]endobj +49 0 obj<>endobj +50 0 obj<>endobj +51 0 obj<>endobj +52 0 obj<>endobj +53 0 obj[49 0 R +50 0 R +51 0 R +52 0 R +]endobj +54 0 obj<>endobj +55 0 obj<>endobj +56 0 obj[54 0 R +55 0 R +]endobj +57 0 obj<>endobj +58 0 obj<>endobj +59 0 obj[57 0 R +58 0 R +]endobj +60 0 obj<>endobj +61 0 obj<>endobj +62 0 obj<>endobj +63 0 obj<>endobj +64 0 obj[60 0 R +61 0 R +62 0 R +63 0 R +]endobj +65 0 obj<>endobj +66 0 obj[65 0 R +]endobj +67 0 obj<>endobj +68 0 obj<>endobj +69 0 obj[67 0 R +68 0 R +]endobj +70 0 obj<>endobj +71 0 obj<>endobj +72 0 obj<>endobj +73 0 obj<>endobj +74 0 obj<>endobj +75 0 obj[70 0 R +71 0 R +72 0 R +73 0 R +74 0 R +]endobj +76 0 obj<>endobj +77 0 obj<>endobj +78 0 obj<>endobj +79 0 obj<>endobj +80 0 obj<>endobj +81 0 obj[76 0 R +77 0 R +78 0 R +79 0 R +80 0 R +]endobj +82 0 obj<>endobj +83 0 obj<>endobj +84 0 obj<>endobj +85 0 obj<>endobj +86 0 obj<>endobj +87 0 obj[82 0 R +83 0 R +84 0 R +85 0 R +86 0 R +]endobj +88 0 obj<>endobj +89 0 obj<>endobj +90 0 obj<>endobj +91 0 obj<>endobj +92 0 obj<>endobj +93 0 obj[88 0 R +89 0 R +90 0 R +91 0 R +92 0 R +]endobj +94 0 obj<>endobj +95 0 obj<>endobj +96 0 obj<>endobj +97 0 obj<>endobj +98 0 obj<>endobj +99 0 obj[94 0 R +95 0 R +96 0 R +97 0 R +98 0 R +]endobj +100 0 obj<>endobj +101 0 obj<>endobj +102 0 obj<>endobj +103 0 obj<>endobj +104 0 obj<>endobj +105 0 obj[100 0 R +101 0 R +102 0 R +103 0 R +104 0 R +]endobj +106 0 obj<>endobj +107 0 obj<>endobj +108 0 obj[106 0 R +107 0 R +]endobj +109 0 obj<>endobj +110 0 obj<>endobj +111 0 obj<>endobj +112 0 obj<>endobj +113 0 obj[109 0 R +110 0 R +111 0 R +112 0 R +]endobj +114 0 obj<>endobj +115 0 obj<>endobj +116 0 obj<>endobj +117 0 obj<>endobj +118 0 obj[114 0 R +115 0 R +116 0 R +117 0 R +]endobj +119 0 obj<>endobj +120 0 obj<>endobj +121 0 obj[119 0 R +120 0 R +]endobj +122 0 obj<>endobj +123 0 obj<>endobj +124 0 obj<>endobj +125 0 obj<>endobj +126 0 obj<>endobj +127 0 obj[122 0 R +123 0 R +124 0 R +125 0 R +126 0 R +]endobj +128 0 obj<>endobj +129 0 obj<>endobj +130 0 obj<>endobj +131 0 obj<>endobj +132 0 obj<>endobj +133 0 obj[128 0 R +129 0 R +130 0 R +131 0 R +132 0 R +]endobj +134 0 obj<>endobj +135 0 obj<>endobj +136 0 obj<>endobj +137 0 obj<>endobj +138 0 obj<>endobj +139 0 obj[134 0 R +135 0 R +136 0 R +137 0 R +138 0 R +]endobj +140 0 obj<>endobj +141 0 obj<>endobj +142 0 obj<>endobj +143 0 obj<>endobj +144 0 obj<>endobj +145 0 obj[140 0 R +141 0 R +142 0 R +143 0 R +144 0 R +]endobj +146 0 obj<>endobj +147 0 obj<>endobj +148 0 obj<>endobj +149 0 obj<>endobj +150 0 obj<>endobj +151 0 obj[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[152 0 R +153 0 R +154 0 R +155 0 R +156 0 R +]endobj +158 0 obj<>endobj +159 0 obj<>endobj +160 0 obj[158 0 R +159 0 R +]endobj +161 0 obj<>endobj +162 0 obj<>endobj +163 0 obj[161 0 R +162 0 R +]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[164 0 R +165 0 R +166 0 R +167 0 R +168 0 R +169 0 R +170 0 R +171 0 R +172 0 R +173 0 R +174 0 R +175 0 R +176 0 R +177 0 R +178 0 R +179 0 R +180 0 R +181 0 R +182 0 R +183 0 R +184 0 R +185 0 R +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 +]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[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 +]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[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 +]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[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 +]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<>endobj +356 0 obj<>endobj +357 0 obj<>endobj +358 0 obj<>endobj +359 0 obj<>endobj +360 0 obj<>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[348 0 R +349 0 R +350 0 R +351 0 R +352 0 R +353 0 R +354 0 R +355 0 R +356 0 R +357 0 R +358 0 R +359 0 R +360 0 R +361 0 R +362 0 R +363 0 R +364 0 R +365 0 R +366 0 R +367 0 R +368 0 R +369 0 R +370 0 R +371 0 R +372 0 R +373 0 R +374 0 R +375 0 R +376 0 R +377 0 R +378 0 R +379 0 R +380 0 R +381 0 R +382 0 R +383 0 R +384 0 R +385 0 R +386 0 R +387 0 R +388 0 R +389 0 R +390 0 R +391 0 R +392 0 R +393 0 R +394 0 R +]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<>endobj +411 0 obj<>endobj +412 0 obj<>endobj +413 0 obj<>endobj +414 0 obj<>endobj +415 0 obj<>endobj +416 0 obj<>endobj +417 0 obj<>endobj +418 0 obj<>endobj +419 0 obj<>endobj +420 0 obj<>endobj +421 0 obj<>endobj +422 0 obj<>endobj +423 0 obj<>endobj +424 0 obj<>endobj +425 0 obj<>endobj +426 0 obj<>endobj +427 0 obj<>endobj +428 0 obj<>endobj +429 0 obj<>endobj +430 0 obj<>endobj +431 0 obj<>endobj +432 0 obj<>endobj +433 0 obj<>endobj +434 0 obj<>endobj +435 0 obj<>endobj +436 0 obj<>endobj +437 0 obj<>endobj +438 0 obj<>endobj +439 0 obj<>endobj +440 0 obj<>endobj +441 0 obj<>endobj +442 0 obj<>endobj +443 0 obj[396 0 R +397 0 R +398 0 R +399 0 R +400 0 R +401 0 R +402 0 R +403 0 R +404 0 R +405 0 R +406 0 R +407 0 R +408 0 R +409 0 R +410 0 R +411 0 R +412 0 R +413 0 R +414 0 R +415 0 R +416 0 R +417 0 R +418 0 R +419 0 R +420 0 R +421 0 R +422 0 R +423 0 R +424 0 R +425 0 R +426 0 R +427 0 R +428 0 R +429 0 R +430 0 R +431 0 R +432 0 R +433 0 R +434 0 R +435 0 R +436 0 R +437 0 R +438 0 R +439 0 R +440 0 R +441 0 R +442 0 R +]endobj +444 0 obj<>endobj +445 0 obj<>endobj +446 0 obj<>endobj +447 0 obj<>endobj +448 0 obj<>endobj +449 0 obj<>endobj +450 0 obj<>endobj +451 0 obj<>endobj +452 0 obj<>endobj +453 0 obj<>endobj +454 0 obj<>endobj +455 0 obj<>endobj +456 0 obj<>endobj +457 0 obj<>endobj +458 0 obj<>endobj +459 0 obj<>endobj +460 0 obj<>endobj +461 0 obj<>endobj +462 0 obj<>endobj +463 0 obj<>endobj +464 0 obj<>endobj +465 0 obj<>endobj +466 0 obj<>endobj +467 0 obj<>endobj +468 0 obj<>endobj +469 0 obj<>endobj +470 0 obj<>endobj +471 0 obj<>endobj +472 0 obj<>endobj +473 0 obj<>endobj +474 0 obj<>endobj +475 0 obj<>endobj +476 0 obj<>endobj +477 0 obj<>endobj +478 0 obj<>endobj +479 0 obj<>endobj +480 0 obj<>endobj +481 0 obj<>endobj +482 0 obj<>endobj +483 0 obj<>endobj +484 0 obj<>endobj +485 0 obj<>endobj +486 0 obj<>endobj +487 0 obj<>endobj +488 0 obj<>endobj +489 0 obj<>endobj +490 0 obj<>endobj +491 0 obj[444 0 R +445 0 R +446 0 R +447 0 R +448 0 R +449 0 R +450 0 R +451 0 R +452 0 R +453 0 R +454 0 R +455 0 R +456 0 R +457 0 R +458 0 R +459 0 R +460 0 R +461 0 R +462 0 R +463 0 R +464 0 R +465 0 R +466 0 R +467 0 R +468 0 R +469 0 R +470 0 R +471 0 R +472 0 R +473 0 R +474 0 R +475 0 R +476 0 R +477 0 R +478 0 R +479 0 R +480 0 R +481 0 R +482 0 R +483 0 R +484 0 R +485 0 R +486 0 R +487 0 R +488 0 R +489 0 R +490 0 R +]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<>endobj +534 0 obj<>endobj +535 0 obj<>endobj +536 0 obj<>endobj +537 0 obj<>endobj +538 0 obj<>endobj +539 0 obj[492 0 R +493 0 R +494 0 R +495 0 R +496 0 R +497 0 R +498 0 R +499 0 R +500 0 R +501 0 R +502 0 R +503 0 R +504 0 R +505 0 R +506 0 R +507 0 R +508 0 R +509 0 R +510 0 R +511 0 R +512 0 R +513 0 R +514 0 R +515 0 R +516 0 R +517 0 R +518 0 R +519 0 R +520 0 R +521 0 R +522 0 R +523 0 R +524 0 R +525 0 R +526 0 R +527 0 R +528 0 R +529 0 R +530 0 R +531 0 R +532 0 R +533 0 R +534 0 R +535 0 R +536 0 R +537 0 R +538 0 R +]endobj +540 0 obj<>endobj +541 0 obj<>endobj +542 0 obj<>endobj +543 0 obj<>endobj +544 0 obj<>endobj +545 0 obj<>endobj +546 0 obj<>endobj +547 0 obj<>endobj +548 0 obj<>endobj +549 0 obj<>endobj +550 0 obj<>endobj +551 0 obj<>endobj +552 0 obj<>endobj +553 0 obj<>endobj +554 0 obj<>endobj +555 0 obj<>endobj +556 0 obj<>endobj +557 0 obj<>endobj +558 0 obj<>endobj +559 0 obj<>endobj +560 0 obj<>endobj +561 0 obj<>endobj +562 0 obj<>endobj +563 0 obj<>endobj +564 0 obj<>endobj +565 0 obj<>endobj +566 0 obj<>endobj +567 0 obj<>endobj +568 0 obj<>endobj +569 0 obj<>endobj +570 0 obj<>endobj +571 0 obj<>endobj +572 0 obj<>endobj +573 0 obj<>endobj +574 0 obj<>endobj +575 0 obj<>endobj +576 0 obj<>endobj +577 0 obj<>endobj +578 0 obj<>endobj +579 0 obj<>endobj +580 0 obj<>endobj +581 0 obj<>endobj +582 0 obj<>endobj +583 0 obj<>endobj +584 0 obj<>endobj +585 0 obj<>endobj +586 0 obj<>endobj +587 0 obj[540 0 R +541 0 R +542 0 R +543 0 R +544 0 R +545 0 R +546 0 R +547 0 R +548 0 R +549 0 R +550 0 R +551 0 R +552 0 R +553 0 R +554 0 R +555 0 R +556 0 R +557 0 R +558 0 R +559 0 R +560 0 R +561 0 R +562 0 R +563 0 R +564 0 R +565 0 R +566 0 R +567 0 R +568 0 R +569 0 R +570 0 R +571 0 R +572 0 R +573 0 R +574 0 R +575 0 R +576 0 R +577 0 R +578 0 R +579 0 R +580 0 R +581 0 R +582 0 R +583 0 R +584 0 R +585 0 R +586 0 R +]endobj +588 0 obj<>endobj +589 0 obj<>endobj +590 0 obj<>endobj +591 0 obj<>endobj +592 0 obj<>endobj +593 0 obj<>endobj +594 0 obj<>endobj +595 0 obj<>endobj +596 0 obj<>endobj +597 0 obj<>endobj +598 0 obj<>endobj +599 0 obj<>endobj +600 0 obj<>endobj +601 0 obj<>endobj +602 0 obj<>endobj +603 0 obj<>endobj +604 0 obj<>endobj +605 0 obj<>endobj +606 0 obj<>endobj +607 0 obj<>endobj +608 0 obj<>endobj +609 0 obj<>endobj +610 0 obj<>endobj +611 0 obj<>endobj +612 0 obj<>endobj +613 0 obj<>endobj +614 0 obj<>endobj +615 0 obj<>endobj +616 0 obj<>endobj +617 0 obj<>endobj +618 0 obj<>endobj +619 0 obj<>endobj +620 0 obj<>endobj +621 0 obj<>endobj +622 0 obj<>endobj +623 0 obj<>endobj +624 0 obj<>endobj +625 0 obj<>endobj +626 0 obj<>endobj +627 0 obj<>endobj +628 0 obj<>endobj +629 0 obj<>endobj +630 0 obj<>endobj +631 0 obj<>endobj +632 0 obj<>endobj +633 0 obj<>endobj +634 0 obj<>endobj +635 0 obj[588 0 R +589 0 R +590 0 R +591 0 R +592 0 R +593 0 R +594 0 R +595 0 R +596 0 R +597 0 R +598 0 R +599 0 R +600 0 R +601 0 R +602 0 R +603 0 R +604 0 R +605 0 R +606 0 R +607 0 R +608 0 R +609 0 R +610 0 R +611 0 R +612 0 R +613 0 R +614 0 R +615 0 R +616 0 R +617 0 R +618 0 R +619 0 R +620 0 R +621 0 R +622 0 R +623 0 R +624 0 R +625 0 R +626 0 R +627 0 R +628 0 R +629 0 R +630 0 R +631 0 R +632 0 R +633 0 R +634 0 R +]endobj +636 0 obj<>endobj +637 0 obj<>endobj +638 0 obj<>endobj +639 0 obj<>endobj +640 0 obj<>endobj +641 0 obj<>endobj +642 0 obj<>endobj +643 0 obj<>endobj +644 0 obj<>endobj +645 0 obj<>endobj +646 0 obj<>endobj +647 0 obj<>endobj +648 0 obj<>endobj +649 0 obj<>endobj +650 0 obj<>endobj +651 0 obj<>endobj +652 0 obj<>endobj +653 0 obj<>endobj +654 0 obj<>endobj +655 0 obj<>endobj +656 0 obj<>endobj +657 0 obj<>endobj +658 0 obj<>endobj +659 0 obj<>endobj +660 0 obj<>endobj +661 0 obj<>endobj +662 0 obj<>endobj +663 0 obj<>endobj +664 0 obj<>endobj +665 0 obj<>endobj +666 0 obj<>endobj +667 0 obj<>endobj +668 0 obj<>endobj +669 0 obj<>endobj +670 0 obj<>endobj +671 0 obj<>endobj +672 0 obj<>endobj +673 0 obj<>endobj +674 0 obj<>endobj +675 0 obj<>endobj +676 0 obj<>endobj +677 0 obj<>endobj +678 0 obj<>endobj +679 0 obj<>endobj +680 0 obj<>endobj +681 0 obj<>endobj +682 0 obj<>endobj +683 0 obj[636 0 R +637 0 R +638 0 R +639 0 R +640 0 R +641 0 R +642 0 R +643 0 R +644 0 R +645 0 R +646 0 R +647 0 R +648 0 R +649 0 R +650 0 R +651 0 R +652 0 R +653 0 R +654 0 R +655 0 R +656 0 R +657 0 R +658 0 R +659 0 R +660 0 R +661 0 R +662 0 R +663 0 R +664 0 R +665 0 R +666 0 R +667 0 R +668 0 R +669 0 R +670 0 R +671 0 R +672 0 R +673 0 R +674 0 R +675 0 R +676 0 R +677 0 R +678 0 R +679 0 R +680 0 R +681 0 R +682 0 R +]endobj +684 0 obj<>endobj +685 0 obj<>endobj +686 0 obj<>endobj +687 0 obj<>endobj +688 0 obj<>endobj +689 0 obj<>endobj +690 0 obj<>endobj +691 0 obj<>endobj +692 0 obj<>endobj +693 0 obj<>endobj +694 0 obj<>endobj +695 0 obj<>endobj +696 0 obj<>endobj +697 0 obj<>endobj +698 0 obj<>endobj +699 0 obj<>endobj +700 0 obj<>endobj +701 0 obj<>endobj +702 0 obj<>endobj +703 0 obj<>endobj +704 0 obj<>endobj +705 0 obj<>endobj +706 0 obj<>endobj +707 0 obj<>endobj +708 0 obj<>endobj +709 0 obj<>endobj +710 0 obj<>endobj +711 0 obj<>endobj +712 0 obj<>endobj +713 0 obj<>endobj +714 0 obj<>endobj +715 0 obj<>endobj +716 0 obj<>endobj +717 0 obj<>endobj +718 0 obj<>endobj +719 0 obj<>endobj +720 0 obj<>endobj +721 0 obj<>endobj +722 0 obj<>endobj +723 0 obj<>endobj +724 0 obj<>endobj +725 0 obj<>endobj +726 0 obj<>endobj +727 0 obj<>endobj +728 0 obj<>endobj +729 0 obj<>endobj +730 0 obj<>endobj +731 0 obj[684 0 R +685 0 R +686 0 R +687 0 R +688 0 R +689 0 R +690 0 R +691 0 R +692 0 R +693 0 R +694 0 R +695 0 R +696 0 R +697 0 R +698 0 R +699 0 R +700 0 R +701 0 R +702 0 R +703 0 R +704 0 R +705 0 R +706 0 R +707 0 R +708 0 R +709 0 R +710 0 R +711 0 R +712 0 R +713 0 R +714 0 R +715 0 R +716 0 R +717 0 R +718 0 R +719 0 R +720 0 R +721 0 R +722 0 R +723 0 R +724 0 R +725 0 R +726 0 R +727 0 R +728 0 R +729 0 R +730 0 R +]endobj +732 0 obj<>endobj +733 0 obj<>endobj +734 0 obj<>endobj +735 0 obj<>endobj +736 0 obj<>endobj +737 0 obj<>endobj +738 0 obj<>endobj +739 0 obj<>endobj +740 0 obj<>endobj +741 0 obj<>endobj +742 0 obj<>endobj +743 0 obj<>endobj +744 0 obj<>endobj +745 0 obj<>endobj +746 0 obj<>endobj +747 0 obj<>endobj +748 0 obj<>endobj +749 0 obj<>endobj +750 0 obj<>endobj +751 0 obj<>endobj +752 0 obj<>endobj +753 0 obj<>endobj +754 0 obj<>endobj +755 0 obj<>endobj +756 0 obj<>endobj +757 0 obj<>endobj +758 0 obj<>endobj +759 0 obj<>endobj +760 0 obj<>endobj +761 0 obj<>endobj +762 0 obj<>endobj +763 0 obj<>endobj +764 0 obj<>endobj +765 0 obj<>endobj +766 0 obj<>endobj +767 0 obj<>endobj +768 0 obj<>endobj +769 0 obj<>endobj +770 0 obj<>endobj +771 0 obj<>endobj +772 0 obj<>endobj +773 0 obj<>endobj +774 0 obj<>endobj +775 0 obj<>endobj +776 0 obj<>endobj +777 0 obj<>endobj +778 0 obj<>endobj +779 0 obj[732 0 R +733 0 R +734 0 R +735 0 R +736 0 R +737 0 R +738 0 R +739 0 R +740 0 R +741 0 R +742 0 R +743 0 R +744 0 R +745 0 R +746 0 R +747 0 R +748 0 R +749 0 R +750 0 R +751 0 R +752 0 R +753 0 R +754 0 R +755 0 R +756 0 R +757 0 R +758 0 R +759 0 R +760 0 R +761 0 R +762 0 R +763 0 R +764 0 R +765 0 R +766 0 R +767 0 R +768 0 R +769 0 R +770 0 R +771 0 R +772 0 R +773 0 R +774 0 R +775 0 R +776 0 R +777 0 R +778 0 R +]endobj +780 0 obj<>endobj +781 0 obj<>endobj +782 0 obj<>endobj +783 0 obj<>endobj +784 0 obj<>endobj +785 0 obj<>endobj +786 0 obj<>endobj +787 0 obj<>endobj +788 0 obj<>endobj +789 0 obj<>endobj +790 0 obj<>endobj +791 0 obj<>endobj +792 0 obj<>endobj +793 0 obj<>endobj +794 0 obj<>endobj +795 0 obj<>endobj +796 0 obj<>endobj +797 0 obj<>endobj +798 0 obj<>endobj +799 0 obj<>endobj +800 0 obj<>endobj +801 0 obj<>endobj +802 0 obj<>endobj +803 0 obj<>endobj +804 0 obj<>endobj +805 0 obj<>endobj +806 0 obj<>endobj +807 0 obj<>endobj +808 0 obj<>endobj +809 0 obj<>endobj +810 0 obj<>endobj +811 0 obj<>endobj +812 0 obj<>endobj +813 0 obj<>endobj +814 0 obj<>endobj +815 0 obj<>endobj +816 0 obj<>endobj +817 0 obj<>endobj +818 0 obj<>endobj +819 0 obj<>endobj +820 0 obj<>endobj +821 0 obj<>endobj +822 0 obj<>endobj +823 0 obj<>endobj +824 0 obj<>endobj +825 0 obj<>endobj +826 0 obj<>endobj +827 0 obj[780 0 R +781 0 R +782 0 R +783 0 R +784 0 R +785 0 R +786 0 R +787 0 R +788 0 R +789 0 R +790 0 R +791 0 R +792 0 R +793 0 R +794 0 R +795 0 R +796 0 R +797 0 R +798 0 R +799 0 R +800 0 R +801 0 R +802 0 R +803 0 R +804 0 R +805 0 R +806 0 R +807 0 R +808 0 R +809 0 R +810 0 R +811 0 R +812 0 R +813 0 R +814 0 R +815 0 R +816 0 R +817 0 R +818 0 R +819 0 R +820 0 R +821 0 R +822 0 R +823 0 R +824 0 R +825 0 R +826 0 R +]endobj +828 0 obj<>endobj +829 0 obj<>endobj +830 0 obj<>endobj +831 0 obj<>endobj +832 0 obj<>endobj +833 0 obj<>endobj +834 0 obj<>endobj +835 0 obj<>endobj +836 0 obj<>endobj +837 0 obj<>endobj +838 0 obj<>endobj +839 0 obj<>endobj +840 0 obj<>endobj +841 0 obj<>endobj +842 0 obj<>endobj +843 0 obj<>endobj +844 0 obj<>endobj +845 0 obj<>endobj +846 0 obj<>endobj +847 0 obj<>endobj +848 0 obj<>endobj +849 0 obj<>endobj +850 0 obj<>endobj +851 0 obj<>endobj +852 0 obj<>endobj +853 0 obj<>endobj +854 0 obj<>endobj +855 0 obj<>endobj +856 0 obj<>endobj +857 0 obj<>endobj +858 0 obj<>endobj +859 0 obj<>endobj +860 0 obj<>endobj +861 0 obj<>endobj +862 0 obj<>endobj +863 0 obj<>endobj +864 0 obj<>endobj +865 0 obj<>endobj +866 0 obj<>endobj +867 0 obj<>endobj +868 0 obj<>endobj +869 0 obj<>endobj +870 0 obj<>endobj +871 0 obj<>endobj +872 0 obj<>endobj +873 0 obj<>endobj +874 0 obj<>endobj +875 0 obj[828 0 R +829 0 R +830 0 R +831 0 R +832 0 R +833 0 R +834 0 R +835 0 R +836 0 R +837 0 R +838 0 R +839 0 R +840 0 R +841 0 R +842 0 R +843 0 R +844 0 R +845 0 R +846 0 R +847 0 R +848 0 R +849 0 R +850 0 R +851 0 R +852 0 R +853 0 R +854 0 R +855 0 R +856 0 R +857 0 R +858 0 R +859 0 R +860 0 R +861 0 R +862 0 R +863 0 R +864 0 R +865 0 R +866 0 R +867 0 R +868 0 R +869 0 R +870 0 R +871 0 R +872 0 R +873 0 R +874 0 R +]endobj +876 0 obj<>endobj +877 0 obj<>endobj +878 0 obj<>endobj +879 0 obj<>endobj +880 0 obj<>endobj +881 0 obj<>endobj +882 0 obj<>endobj +883 0 obj<>endobj +884 0 obj<>endobj +885 0 obj<>endobj +886 0 obj<>endobj +887 0 obj<>endobj +888 0 obj<>endobj +889 0 obj<>endobj +890 0 obj<>endobj +891 0 obj<>endobj +892 0 obj<>endobj +893 0 obj<>endobj +894 0 obj<>endobj +895 0 obj<>endobj +896 0 obj<>endobj +897 0 obj<>endobj +898 0 obj<>endobj +899 0 obj<>endobj +900 0 obj<>endobj +901 0 obj<>endobj +902 0 obj<>endobj +903 0 obj<>endobj +904 0 obj<>endobj +905 0 obj<>endobj +906 0 obj<>endobj +907 0 obj<>endobj +908 0 obj<>endobj +909 0 obj<>endobj +910 0 obj<>endobj +911 0 obj<>endobj +912 0 obj<>endobj +913 0 obj<>endobj +914 0 obj<>endobj +915 0 obj<>endobj +916 0 obj<>endobj +917 0 obj<>endobj +918 0 obj<>endobj +919 0 obj<>endobj +920 0 obj<>endobj +921 0 obj<>endobj +922 0 obj<>endobj +923 0 obj[876 0 R +877 0 R +878 0 R +879 0 R +880 0 R +881 0 R +882 0 R +883 0 R +884 0 R +885 0 R +886 0 R +887 0 R +888 0 R +889 0 R +890 0 R +891 0 R +892 0 R +893 0 R +894 0 R +895 0 R +896 0 R +897 0 R +898 0 R +899 0 R +900 0 R +901 0 R +902 0 R +903 0 R +904 0 R +905 0 R +906 0 R +907 0 R +908 0 R +909 0 R +910 0 R +911 0 R +912 0 R +913 0 R +914 0 R +915 0 R +916 0 R +917 0 R +918 0 R +919 0 R +920 0 R +921 0 R +922 0 R +]endobj +924 0 obj<>endobj +925 0 obj<>endobj +926 0 obj<>endobj +927 0 obj<>endobj +928 0 obj<>endobj +929 0 obj<>endobj +930 0 obj[924 0 R +925 0 R +926 0 R +927 0 R +928 0 R +929 0 R +]endobj +931 0 obj<>endobj +932 0 obj<>endobj +933 0 obj<>endobj +934 0 obj<>endobj +935 0 obj<>endobj +936 0 obj<>endobj +937 0 obj<>endobj +938 0 obj<>endobj +939 0 obj<>endobj +940 0 obj<>endobj +941 0 obj<>endobj +942 0 obj<>endobj +943 0 obj<>endobj +944 0 obj<>endobj +945 0 obj<>endobj +946 0 obj<>endobj +947 0 obj<>endobj +948 0 obj<>endobj +949 0 obj<>endobj +950 0 obj<>endobj +951 0 obj<>endobj +952 0 obj<>endobj +953 0 obj<>endobj +954 0 obj<>endobj +955 0 obj<>endobj +956 0 obj<>endobj +957 0 obj<>endobj +958 0 obj<>endobj +959 0 obj<>endobj +960 0 obj<>endobj +961 0 obj<>endobj +962 0 obj<>endobj +963 0 obj<>endobj +964 0 obj<>endobj +965 0 obj<>endobj +966 0 obj<>endobj +967 0 obj<>endobj +968 0 obj<>endobj +969 0 obj<>endobj +970 0 obj<>endobj +971 0 obj<>endobj +972 0 obj<>endobj +973 0 obj<>endobj +974 0 obj<>endobj +975 0 obj<>endobj +976 0 obj<>endobj +977 0 obj<>endobj +978 0 obj<>endobj +979 0 obj<>endobj +980 0 obj<>endobj +981 0 obj<>endobj +982 0 obj<>endobj +983 0 obj<>endobj +984 0 obj<>endobj +985 0 obj<>endobj +986 0 obj<>endobj +987 0 obj<>endobj +988 0 obj<>endobj +989 0 obj<>endobj +990 0 obj<>endobj +991 0 obj<>endobj +992 0 obj<>endobj +993 0 obj<>endobj +994 0 obj<>endobj +995 0 obj<>endobj +996 0 obj<>endobj +997 0 obj<>endobj +998 0 obj<>endobj +999 0 obj<>endobj +1000 0 obj<>endobj +1001 0 obj<>endobj +1002 0 obj<>endobj +1003 0 obj<>endobj +1004 0 obj<>endobj +1005 0 obj<>endobj +1006 0 obj<>endobj +1007 0 obj<>endobj +1008 0 obj<>endobj +1009 0 obj<>endobj +1010 0 obj<>endobj +1011 0 obj<>endobj +1012 0 obj<>endobj +1013 0 obj<>endobj +1014 0 obj<>endobj +1015 0 obj<>endobj +1016 0 obj<>endobj +1017 0 obj<>endobj +1018 0 obj<>endobj +1019 0 obj<>endobj +1020 0 obj<>endobj +1021 0 obj<>endobj +1022 0 obj<>endobj +1023 0 obj<>endobj +1024 0 obj<>endobj +1025 0 obj<>endobj +1026 0 obj<>endobj +1027 0 obj<>endobj +1028 0 obj<>endobj +1029 0 obj<>endobj +1030 0 obj<>endobj +1031 0 obj<>endobj +1032 0 obj<>endobj +1033 0 obj<>endobj +1034 0 obj<>endobj +1035 0 obj<>endobj +1036 0 obj<>endobj +1037 0 obj<>endobj +1038 0 obj<>endobj +1039 0 obj<>endobj +1040 0 obj<>endobj +1041 0 obj<>endobj +1042 0 obj<>endobj +1043 0 obj<>endobj +1044 0 obj<>endobj +1045 0 obj<>endobj +1046 0 obj<>endobj +1047 0 obj<>endobj +1048 0 obj<>endobj +1049 0 obj<>endobj +1050 0 obj<>endobj +1051 0 obj<>endobj +1052 0 obj<>endobj +1053 0 obj<>endobj +1054 0 obj<>endobj +1055 0 obj<>endobj +1056 0 obj<>endobj +1057 0 obj<>endobj +1058 0 obj<>endobj +1059 0 obj<>endobj +1060 0 obj<>endobj +1061 0 obj<>endobj +1062 0 obj<>endobj +1063 0 obj<>endobj +1064 0 obj<>endobj +1065 0 obj<>endobj +1066 0 obj<>endobj +1067 0 obj<>endobj +1068 0 obj<>endobj +1069 0 obj<>endobj +1070 0 obj<>endobj +1071 0 obj<>endobj +1072 0 obj<>endobj +1073 0 obj<>endobj +1074 0 obj<>endobj +1075 0 obj<>endobj +1076 0 obj<>endobj +1077 0 obj<>endobj +1078 0 obj<>endobj +1079 0 obj<>endobj +1080 0 obj<>endobj +1081 0 obj<>endobj +1082 0 obj<>endobj +1083 0 obj<>endobj +1084 0 obj<>endobj +1085 0 obj<>endobj +1086 0 obj<>endobj +1087 0 obj<>endobj +1088 0 obj<>endobj +1089 0 obj<>endobj +1090 0 obj<>endobj +1091 0 obj<>endobj +1092 0 obj<>endobj +1093 0 obj<>endobj +1094 0 obj<>endobj +1095 0 obj<>endobj +1096 0 obj<>endobj +1097 0 obj<>endobj +1098 0 obj<>endobj +1099 0 obj<>endobj +1100 0 obj<>endobj +1101 0 obj<>endobj +1102 0 obj<>endobj +1103 0 obj<>endobj +1104 0 obj<>endobj +1105 0 obj<>endobj +1106 0 obj<>endobj +1107 0 obj<>endobj +1108 0 obj<>endobj +1109 0 obj<>endobj +1110 0 obj<>endobj +1111 0 obj<>endobj +1112 0 obj<>endobj +1113 0 obj<>endobj +1114 0 obj<>endobj +1115 0 obj<>endobj +1116 0 obj<>endobj +1117 0 obj<>endobj +1118 0 obj<>endobj +1119 0 obj<>endobj +1120 0 obj<>endobj +1121 0 obj<>endobj +1122 0 obj<>endobj +1123 0 obj<>endobj +1124 0 obj<>endobj +1125 0 obj<>endobj +1126 0 obj<>endobj +1127 0 obj<>endobj +1128 0 obj<>endobj +1129 0 obj<>endobj +1130 0 obj<>endobj +1131 0 obj<>endobj +1132 0 obj<>endobj +1133 0 obj<>endobj +1134 0 obj<>endobj +1135 0 obj<>endobj +1136 0 obj<>endobj +1137 0 obj<>endobj +1138 0 obj<>endobj +1139 0 obj<>endobj +1140 0 obj<>endobj +1141 0 obj<>endobj +1142 0 obj<>endobj +1143 0 obj<>endobj +1144 0 obj<>endobj +1145 0 obj<>endobj +1146 0 obj<>endobj +1147 0 obj<>endobj +1148 0 obj<>endobj +1149 0 obj<>endobj +1150 0 obj<>endobj +1151 0 obj<>endobj +1152 0 obj<>endobj +1153 0 obj<>endobj +1154 0 obj<>endobj +1155 0 obj<>endobj +1156 0 obj<>endobj +1157 0 obj<>endobj +1158 0 obj<>endobj +1159 0 obj<>endobj +1160 0 obj<>endobj +1161 0 obj<>endobj +1162 0 obj<>endobj +1163 0 obj<>endobj +1164 0 obj<>endobj +1165 0 obj<>endobj +1166 0 obj<>endobj +1167 0 obj<>endobj +1168 0 obj<>endobj +1169 0 obj<>endobj +1170 0 obj<>endobj +1171 0 obj<>endobj +1172 0 obj<>endobj +1173 0 obj<>endobj +1174 0 obj<>endobj +1175 0 obj<>endobj +1176 0 obj<>endobj +1177 0 obj<>endobj +1178 0 obj<>endobj +1179 0 obj<>endobj +1180 0 obj<>endobj +1181 0 obj<>endobj +1182 0 obj<>endobj +1183 0 obj<>endobj +1184 0 obj<>endobj +1185 0 obj<>endobj +1186 0 obj<>endobj +1187 0 obj<>endobj +1188 0 obj<>endobj +1189 0 obj<>endobj +1190 0 obj<>endobj +1191 0 obj<>endobj +1192 0 obj<>endobj +1193 0 obj<>endobj +1194 0 obj<>endobj +1195 0 obj<>endobj +1196 0 obj<>endobj +1197 0 obj<>endobj +1198 0 obj<>endobj +1199 0 obj<>endobj +1200 0 obj<>endobj +1201 0 obj<>endobj +1202 0 obj<>endobj +1203 0 obj<>endobj +1204 0 obj<>endobj +1205 0 obj<>endobj +1206 0 obj<>endobj +1207 0 obj<>endobj +1208 0 obj<>endobj +1209 0 obj<>endobj +1210 0 obj<>endobj +1211 0 obj<>endobj +1212 0 obj<>endobj +1213 0 obj<>endobj +1214 0 obj<>endobj +1215 0 obj<>endobj +1216 0 obj<>endobj +1217 0 obj<>endobj +1218 0 obj<>endobj +1219 0 obj<>endobj +1220 0 obj<>endobj +1221 0 obj<>endobj +1222 0 obj<>endobj +1223 0 obj<>endobj +1224 0 obj<>endobj +1225 0 obj<>endobj +1226 0 obj<>endobj +1227 0 obj<>endobj +1228 0 obj<>endobj +1229 0 obj<>endobj +1230 0 obj<>endobj +1231 0 obj<>endobj +1232 0 obj<>endobj +1233 0 obj<>endobj +1234 0 obj<>endobj +1235 0 obj<>endobj +1236 0 obj<>endobj +1237 0 obj<>endobj +1238 0 obj<>endobj +1239 0 obj<>endobj +1240 0 obj<>endobj +1241 0 obj<>endobj +1242 0 obj<>endobj +1243 0 obj<>endobj +1244 0 obj<>endobj +1245 0 obj<>endobj +1246 0 obj<>endobj +1247 0 obj<>endobj +1248 0 obj<>endobj +1249 0 obj<>endobj +1250 0 obj<>endobj +1251 0 obj<>endobj +1252 0 obj<>endobj +1253 0 obj<>endobj +1254 0 obj<>endobj +1255 0 obj<>endobj +1256 0 obj<>endobj +1257 0 obj<>endobj +1258 0 obj<>endobj +1259 0 obj<>endobj +1260 0 obj<>endobj +1261 0 obj<>endobj +1262 0 obj<>endobj +1263 0 obj<>endobj +1264 0 obj<>endobj +1265 0 obj<>endobj +1266 0 obj<>endobj +1267 0 obj<>endobj +1268 0 obj<>endobj +1269 0 obj<>endobj +1270 0 obj<>endobj +1271 0 obj<>endobj +1272 0 obj<>endobj +1273 0 obj<>endobj +1274 0 obj<>endobj +1275 0 obj<>endobj +1276 0 obj<>endobj +1277 0 obj<>endobj +1278 0 obj<>endobj +1279 0 obj<>endobj +1280 0 obj<>endobj +1281 0 obj<>endobj +1282 0 obj<>endobj +1283 0 obj<>endobj +1284 0 obj<>endobj +1285 0 obj<>endobj +1286 0 obj<>endobj +1287 0 obj<>endobj +1288 0 obj<>endobj +1289 0 obj<>endobj +1290 0 obj<>endobj +1291 0 obj<>endobj +1292 0 obj<>endobj +1293 0 obj<>endobj +1294 0 obj<>endobj +1295 0 obj<>endobj +1296 0 obj<>endobj +1297 0 obj<>endobj +1298 0 obj<>endobj +1299 0 obj<>endobj +1300 0 obj<>endobj +1301 0 obj<>endobj +1302 0 obj<>endobj +1303 0 obj<>endobj +1304 0 obj<>endobj +1305 0 obj<>endobj +1306 0 obj<>endobj +1307 0 obj<>endobj +1308 0 obj<>endobj +1309 0 obj<>endobj +1310 0 obj<>endobj +1311 0 obj<>endobj +1312 0 obj<>endobj +1313 0 obj<>endobj +1314 0 obj<>endobj +1315 0 obj<>endobj +1316 0 obj<>endobj +1317 0 obj<>endobj +1318 0 obj<>endobj +1319 0 obj<>endobj +1320 0 obj<>endobj +1321 0 obj<>endobj +1322 0 obj<>endobj +1323 0 obj<>endobj +1324 0 obj<>endobj +1325 0 obj<>endobj +1326 0 obj<>endobj +1327 0 obj<>endobj +1328 0 obj<>endobj +1329 0 obj<>endobj +1330 0 obj<>endobj +1331 0 obj<>endobj +1332 0 obj<>endobj +1333 0 obj<>endobj +1334 0 obj<>endobj +1335 0 obj<>endobj +1336 0 obj<>endobj +1337 0 obj<>endobj +1338 0 obj<>endobj +1339 0 obj<>endobj +1340 0 obj<>endobj +1341 0 obj<>endobj +1342 0 obj<>endobj +1343 0 obj<>endobj +1344 0 obj<>endobj +1345 0 obj<>endobj +1346 0 obj<>endobj +1347 0 obj<>endobj +1348 0 obj<>endobj +1349 0 obj<>endobj +1350 0 obj<>endobj +1351 0 obj<>endobj +1352 0 obj<>endobj +1353 0 obj<>endobj +1354 0 obj<>endobj +1355 0 obj<>endobj +1356 0 obj<>endobj +1357 0 obj<>endobj +1358 0 obj<>endobj +1359 0 obj<>endobj +1360 0 obj<>endobj +1361 0 obj<>endobj +1362 0 obj<>endobj +1363 0 obj<>endobj +1364 0 obj<>endobj +1365 0 obj<>endobj +1366 0 obj<>endobj +1367 0 obj<>endobj +1368 0 obj<>endobj +1369 0 obj<>endobj +1370 0 obj<>endobj +1371 0 obj<>endobj +1372 0 obj<>endobj +1373 0 obj<>endobj +1374 0 obj<>endobj +1375 0 obj<>endobj +1376 0 obj<>endobj +1377 0 obj<>endobj +1378 0 obj<>endobj +1379 0 obj<>endobj +1380 0 obj<>endobj +1381 0 obj<>endobj +1382 0 obj<>endobj +1383 0 obj<>endobj +1384 0 obj<>endobj +1385 0 obj<>endobj +1386 0 obj<>endobj +1387 0 obj<>endobj +1388 0 obj<>endobj +1389 0 obj<>endobj +1390 0 obj<>endobj +1391 0 obj<>endobj +1392 0 obj<>endobj +1393 0 obj<>endobj +1394 0 obj<>endobj +1395 0 obj<>endobj +1396 0 obj<>endobj +1397 0 obj<>endobj +1398 0 obj<>endobj +1399 0 obj<>endobj +1400 0 obj<>endobj +1401 0 obj<>endobj +1402 0 obj<>endobj +1403 0 obj<>endobj +1404 0 obj<>endobj +1405 0 obj<>endobj +1406 0 obj<>endobj +1407 0 obj<>endobj +1408 0 obj<>endobj +1409 0 obj<>endobj +1410 0 obj<>endobj +1411 0 obj<>endobj +1412 0 obj<>endobj +1413 0 obj<>endobj +1414 0 obj<>endobj +1415 0 obj<>endobj +1416 0 obj<>endobj +1417 0 obj<>endobj +1418 0 obj<>endobj +1419 0 obj<>endobj +1420 0 obj<>endobj +1421 0 obj<>endobj +1422 0 obj<>endobj +1423 0 obj<>endobj +1424 0 obj<>endobj +1425 0 obj<>endobj +1426 0 obj<>endobj +1427 0 obj<>endobj +1428 0 obj<>endobj +1429 0 obj<>endobj +1430 0 obj<>endobj +1431 0 obj<>endobj +1432 0 obj<>endobj +1433 0 obj<>endobj +1434 0 obj<>endobj +1435 0 obj<>endobj +1436 0 obj<>endobj +1437 0 obj<>endobj +1438 0 obj<>endobj +1439 0 obj<>endobj +1440 0 obj<>endobj +1441 0 obj<>endobj +1442 0 obj<>endobj +1443 0 obj<>endobj +1444 0 obj<>endobj +1445 0 obj<>endobj +1446 0 obj<>endobj +1447 0 obj<>endobj +1448 0 obj<>endobj +1449 0 obj<>endobj +1450 0 obj<>endobj +1451 0 obj<>endobj +1452 0 obj<>endobj +1453 0 obj<>endobj +1454 0 obj<>endobj +1455 0 obj<>endobj +1456 0 obj<>endobj +1457 0 obj<>endobj +1458 0 obj<>endobj +1459 0 obj<>endobj +1460 0 obj<>endobj +1461 0 obj<>endobj +1462 0 obj<>endobj +1463 0 obj<>endobj +1464 0 obj<>endobj +1465 0 obj<>endobj +1466 0 obj<>endobj +1467 0 obj<>endobj +1468 0 obj<>endobj +1469 0 obj<>endobj +1470 0 obj<>endobj +1471 0 obj<>endobj +1472 0 obj<>endobj +1473 0 obj<>endobj +1474 0 obj<>endobj +1475 0 obj<>endobj +1476 0 obj<>endobj +1477 0 obj<>endobj +1478 0 obj<>endobj +1479 0 obj<>endobj +1480 0 obj<>endobj +1481 0 obj<>endobj +1482 0 obj<>endobj +1483 0 obj<>endobj +1484 0 obj<>endobj +1485 0 obj<>endobj +1486 0 obj<>endobj +1487 0 obj<>endobj +1488 0 obj<>endobj +1489 0 obj<>endobj +1490 0 obj<>endobj +1491 0 obj<>endobj +1492 0 obj<>endobj +1493 0 obj<>endobj +1494 0 obj<>endobj +1495 0 obj<>endobj +1496 0 obj<>endobj +1497 0 obj<>endobj +1498 0 obj<>endobj +1499 0 obj<>endobj +1500 0 obj<>endobj +1501 0 obj<>endobj +1502 0 obj<>endobj +1503 0 obj<>endobj +1504 0 obj<>endobj +1505 0 obj<>endobj +1506 0 obj<>endobj +1507 0 obj<>endobj +1508 0 obj<>endobj +1509 0 obj<>endobj +1510 0 obj<>endobj +1511 0 obj<>endobj +1512 0 obj<>endobj +1513 0 obj<>endobj +1514 0 obj<>endobj +1515 0 obj<>endobj +1516 0 obj<>endobj +1517 0 obj<>endobj +1518 0 obj<>endobj +1519 0 obj<>endobj +1520 0 obj<>endobj +1521 0 obj<>endobj +1522 0 obj<>endobj +1523 0 obj<>endobj +1524 0 obj<>endobj +1525 0 obj<>endobj +1526 0 obj<>endobj +1527 0 obj<>endobj +1528 0 obj<>endobj +1529 0 obj<>endobj +1530 0 obj<>endobj +1531 0 obj<>endobj +1532 0 obj<>endobj +1533 0 obj<>endobj +1534 0 obj<>endobj +1535 0 obj<>endobj +1536 0 obj<>endobj +1537 0 obj<>endobj +1538 0 obj<>endobj +1539 0 obj<>endobj +1540 0 obj<>endobj +1541 0 obj<>endobj +1542 0 obj<>endobj +1543 0 obj<>endobj +1544 0 obj<>endobj +1545 0 obj<>endobj +1546 0 obj<>endobj +1547 0 obj<>endobj +1548 0 obj<>endobj +1549 0 obj<>endobj +1550 0 obj<>endobj +1551 0 obj<>endobj +1552 0 obj<>endobj +1553 0 obj<>endobj +1554 0 obj<>endobj +1555 0 obj<>endobj +1556 0 obj<>endobj +1557 0 obj<>endobj +1558 0 obj<>endobj +1559 0 obj<>endobj +1560 0 obj<>endobj +1561 0 obj<>endobj +1562 0 obj<>endobj +1563 0 obj<>endobj +1564 0 obj<>endobj +1565 0 obj<>endobj +1566 0 obj<>endobj +1567 0 obj<>endobj +1568 0 obj<>endobj +1569 0 obj<>endobj +1570 0 obj<>endobj +1571 0 obj<>endobj +1572 0 obj<>endobj +1573 0 obj<>endobj +1574 0 obj<>endobj +1575 0 obj<>endobj +1576 0 obj<>endobj +1577 0 obj<>endobj +1578 0 obj<>endobj +1579 0 obj<>endobj +1580 0 obj<>endobj +1581 0 obj<>endobj +1582 0 obj<>endobj +1583 0 obj<>endobj +1584 0 obj<>endobj +1585 0 obj<>endobj +1586 0 obj<>endobj +1587 0 obj<>endobj +1588 0 obj<>endobj +1589 0 obj<>endobj +1590 0 obj<>endobj +1591 0 obj<>endobj +1592 0 obj<>endobj +1593 0 obj<>endobj +1594 0 obj<>endobj +1595 0 obj<>endobj +1596 0 obj<>endobj +1597 0 obj<>endobj +1598 0 obj<>endobj +1599 0 obj<>endobj +1600 0 obj<>endobj +1601 0 obj<>endobj +1602 0 obj<>endobj +1603 0 obj<>endobj +1604 0 obj<>endobj +1605 0 obj<>endobj +1606 0 obj<>endobj +1607 0 obj<>endobj +1608 0 obj<>endobj +1609 0 obj<>endobj +1610 0 obj<>endobj +1611 0 obj<>endobj +1612 0 obj<>endobj +1613 0 obj<>endobj +1614 0 obj<>endobj +1615 0 obj<>endobj +1616 0 obj<>endobj +1617 0 obj<>endobj +1618 0 obj<>endobj +1619 0 obj<>endobj +1620 0 obj<>endobj +1621 0 obj<>endobj +1622 0 obj<>endobj +1623 0 obj<>endobj +1624 0 obj<>endobj +1625 0 obj<>endobj +1626 0 obj<>endobj +1627 0 obj<>endobj +1628 0 obj<>endobj +1629 0 obj<>endobj +1630 0 obj<>endobj +1631 0 obj<>endobj +1632 0 obj<>endobj +1633 0 obj<>endobj +1634 0 obj<>endobj +1635 0 obj<>endobj +1636 0 obj<>endobj +1637 0 obj<>endobj +1638 0 obj<>endobj +1639 0 obj<>endobj +1640 0 obj<>endobj +1641 0 obj<>endobj +1642 0 obj<>endobj +1643 0 obj<>endobj +1644 0 obj<>endobj +1645 0 obj<>endobj +1646 0 obj<>endobj +1647 0 obj<>endobj +1648 0 obj<>endobj +1649 0 obj<>endobj +1650 0 obj<>endobj +1651 0 obj<>endobj +1652 0 obj<>endobj +1653 0 obj<>endobj +1654 0 obj<>endobj +1655 0 obj<>endobj +1656 0 obj<>endobj +1657 0 obj<>endobj +1658 0 obj<>endobj +1659 0 obj<>endobj +1660 0 obj<>endobj +1661 0 obj<>endobj +1662 0 obj<>endobj +1663 0 obj<>endobj +1664 0 obj<>endobj +1665 0 obj<>endobj +1666 0 obj<>endobj +1667 0 obj<>endobj +1668 0 obj<>endobj +1669 0 obj<>endobj +1670 0 obj<>endobj +1671 0 obj<>endobj +1672 0 obj<>endobj +1673 0 obj<>endobj +1674 0 obj<>endobj +1675 0 obj<>endobj +1676 0 obj<>endobj +1677 0 obj<>endobj +1678 0 obj<>endobj +1679 0 obj<>endobj +1680 0 obj<>endobj +1681 0 obj<>endobj +1682 0 obj<>endobj +1683 0 obj<>endobj +1684 0 obj<>endobj +1685 0 obj<>endobj +1686 0 obj<>endobj +1687 0 obj<>>>>>endobj +1688 0 obj<>stream +xÚìÏsë8rÇIŠºÌ‰öŒî´üt§çyšÝ­ÚJñÙfvçÖ$ÁÊ!•S*Ç6•üÿ±~X"H€èn$è5¦jêÙE|ˆÆ·@ƒúÇOßòýÛßò?=å¿ýžÿçÿô,~*ÅOÿÈÛÿù×?þøÛï¿ÿºÏÿü—_Ÿò§§§·kýñõ¥ù÷¯|­ÿöœþº?•ßNå÷SùË©¼œÊ¿žÊ¿üÇ×?òÿýŸÿû¯¯ÿ–ÿíÛ׿ç‡oß¾>ÃKþ=ÿãõ§öcøä²+âõi»Ý>ÜËÛ?¶ß_—Î%^¶wY¤*w÷¯ËäOj¤Üöû¸ē‰é½Ü?–KáÂC]о/ëå!"—x[ÎõœE¼r˜ë‰KåÒ!˜¾rÛg޹^òȾü\ÆÕÊÏ3s=GžJRÎÉõ-òVâÃl\ŽuЄõV¾ÌÂ%²( + ‚B¹ü29×$X,0X –€Åƒ %ƒ/° ¬(ÚMÄåÝoÙ9h6×ÄXo`å\ûhò’LÀõ#𡬼sÕÑ,åÏ\M6A!|…gi,A +Ú Ñ ê£s5Ѭåà‹+›— 9Ä`™ãÅ`ž‹,öD.1?V{àÊàŠRç\uD98æY\‰c®}HÙ8媣`Jé++D91WT蚐°ŒÒË TÔ  LÔ‹Š4ðZåªBÃ2t,OãQ ÔxŒsÆq‰±FãzX¢Æ#F,Ï%£FL×]w÷Ûí—×cy>|ðÛa0IwÅ÷_†ƒüxÂ[‡ÿîŠG’þÅ˃ŸßÝuoœ*=[ í,¸ö~ºªÛk[ça=xì.Bú±àæØ\ìPƒ–.Î$[q¹¸¡==·aMJ&³»XéԜ.K™\¬@ž› É貘ÇUùÑv‡]¶cqeSÙà՛eN¤ܯjؤ½s’  ®|²¡ÅϼJé\Í Xd°˜ÎEùØÍÉÜZ9ƹfÂ"‚­¨\Õ FÈ1ŒȕυEÛи'’ –Y¹0p7ñú¥uZj+Cg‘¼c,Òé« …«rÎX•½ÅÍÁ‘jÄ¥{.B J<—°ÒlKÃ7D=Ì:¸ÎåÛÁÉ %i=•œkˆàBf½ .Ú`Ø`¹Š¹2O”,Á W­Ç’ó ìÍПR4q‡ãÚa…„–¤8®´&1Š«žÙ#3ì€á«aÚz/8 [c¸²0Dƒ¢õ ‚«æfóuXiæ*B J‡íÌ\Y OjOjäªÃê.d‡%F®"°îBú°ÒĕÖ]È'½1p5Á¸dZ“RW\wá¢ÄÄÀ•6ºÐRVŽr‰» 7æw£\u€Ý…[FJG¹*OŠ…²¢d”+ (2$*ÇVå'ÆB ÃRåÓ©¹Z’ Wå“s! q5ÂÀÚÛ=W¢È£­ÔrAˆ"v@;-W¨jàLi­ã¡ªnè¯t\5-4”=Ùí§ž±¿ÿ.Ï´’T¹Æúù=¾aÀ +¢6(®–KH·Kh%ºÖRÕÓbQ®•–ër›®Îa‡Àà ¯Çé¹ £^ >ÜÌіœáµCrí´\MçùÖ 1£$UsÑys¥Z®³í%·NH)}¢æÊ‰Îkœ+ÑsÝ´BPf=ègŒàp‡åz7.×MÛk¼b”¾Tq5ÔÊÀµÑrÝD° ¬•T؇ô¹WŠçZ鹊÷G”Q&ß V<זByW¤çª/ŸÕPÌ1PRWF4C#×NËu¾×úü+ü’QØV +.A5C#WªçڟòáªÕr[¬àª©fhäŠõ\盽§5Rì•K,×êZ[Éu6Ž;êÊ12BªWNZ,×:{—'%WG¤(³ÔgO@• ž«x j®Š5K5†ˆëWC6Ãq®ZÂp ÖbI…Ó5 ÊFÒâ¹Ä»Y¨¹®&EZ,ip-â\9%pžê¹*֚Nè(; +\n£á¬5;c+\ŒôÅq®æ" +®K‰kvª‰@“¤¥pµ¥×qgéB™ÐdcMãº(½Ž«àôWòD@“ë¢ô:®Œ3¾êÙwCÅuQz WÍÛÃÈ0’ ¤h#!r]”^ÃUðûMÏ%s Æð2r•^Õñ6g +ÌÃ’lì¨\g¥Ws5Ì]Œ +㘁´¶ÑR¹ÎJ¯æ½ØER2WÁ^f®“Ò«¹rfæŽÀ8f DQ)ëd݅~^¹e¢IàkSYŽ­\§Öç*®³Ý Fȑ#š ”(ªT?º²k ±ÌukDŸ+?krN7Ä="àVÌµë>š>h¸Þ;а›‚]†Yw¹k6+IlºŠšô¸ Wuáiè†X!dr¸Ñ˜ÄjøCýsȵèÝJ´§•¸rŽlH[âã‹:\…’K\[°'¢@Ø¢C­I¤€]Ÿ«VrU×Ê=öEèà£ÃDïû¯´ùÖṌŸêsí¯#èùVž«áxåÛ-â;^WÈ\OÌɱonn0¾d=äª\ÝT”‚lˆ{ó€¼0ÚT¹WWojò$ ð\{–l lbÕ¹.¶*qeÝKž„‰×ñÒáÊY²Ñ˜×Ó{Šyq—KΈÚ{ÈhzªX¯üPy8Å:F—« »òúh9ÔNþnï5ùÒ*¹Ä€+“,¯ñª è¨Wo'ÍéŧñýGH©\SßËy°†ÇeŽæãvQ°2Ÿ,’+çEQÁse¼(*t.a#‡s5–r*W͍çª>š^¸ +vt6מ͕4™¿peM/\œ¥ùp‰'óg®úÃÉ<–k2ߝÎ-‡͋ó·•Ü:\[æ»uîªßFwÒ²ßmµwpœOm›.Ò,²Î-ï\·u›þà,•\×FÍÕI¿\¹r¶ûRãkT§×ćk¥äjÔûËÛ}©4fÜkbÄኔ\¹z߁¿h£¶W]nj¯‰;×NÁU UPn9Ár­4áËNŕr¸RW6|ŒŽ¹Î«Ëë51áp%C®wшﲫÝÊ-§h®š+Vqõó¡¸g¯r~ô'/ÙÅlp\ëQ®Ó¿^òHjÁZv,¥Šk£tEr<Џ¨ëdÞ7ÛnlÌ\—᯻?"éx@·‰+×à¢Zr—Ûj{‡àꤥÈ]|Ëíé71âp .’7.y<€ +£®[‘"K~­lâŽÃÕ¿(—óM +-áðì8—Ðpz®”ÃÕ¿¨7RNf™*Œj1\·Ùÿj®˜ÃÕ»¨ðTà¹b\Šã|f.ÅEußÁnßÊ#`ÂÃĞk¨Šã|f.ÝÀT5_ŽÜp ×^­óŠã|®áE…ÒÁ&ŒJ[=Ì®9·r‡Çù\Ër¥#Bq­Q\µÚ՚8JqœÁ5¼HËU;â*”ñÆË- é5qxœÁ5¼(S:"×Ã%¢"ÎSÇù0\ƒ‹´\?Œê´áò;ô¼RqœÃ5¸¨[ývGסµœm”MçÃp .Òr?ŒjÕ£YU4ñ"Ú4®þE\-š+Uý6.5MìçCqõ/Òr¹ê^,ÕMìçCqõ/Òríùáa«68Íòþ ‰ýã|(®þEY/Mõʕ;ãŠK W'T•šØ;·ãê]ÄçJ\ñ®óۋ_¾,{lÔMìçÃqõ.Ê;Š-qen¸:ù‡Ýxã¼ì‘ª›Ø;·ãê]4ˆ£*,WÚâæ)­Š«ó~(EO¢Må’/Ú÷#¢âÂùåªÇ¸äã|H.ÅÀn÷X®µW£‹ç¯AeNä’/ªúC%;s Ï\BsŠCqœÉ%_T÷$[DX®W;Ê.é"Ñ Í« ¸—|Q&°üÂeÎ=Üy䒎óa¹ä‹ +E2þW=/WÁá’.ªn»Ê·EÞÙ¹j—t‘è¶²¾Æ6ÓJ\‚Ã%_”ßö¿ž#W铫{œÍ%_T ö+Càª8\òE½H0?qÙL—Q\Ù8WÃá’/’gÆé>®Îq>ès¥”ºór=ŸÞa?bšK©;3×Cÿøšü²¡ÎæuÕ»ꝪHqPJÛ:k®|¾!çéw·§†u\y1Ô׏áŒF~™WsÛìø9QeäÚÉÔ—Pì(É/4¬®KüuòÈȵ™‚ TSë¼;Àz齺 ®u+ M?\™j« ºã “Òdúu\©l)^¸š÷§»nÝî«ko»õʺ ®Dºµ®êºQ(¾unڑÀ[v…².Ÿ«öÉUtv¬÷7ïÒqY·äsM]Õ2¿ú®òöNå“+ª›v^Ȭ©K㊯ۧoƒ8ñƕu—áòžÒߌ§©KãJ®£0qÙÄóҟá¦×VËIÚªº$®Õõq¼=™t®êöÓ5ä$mU]WÚ}tk;.CúáõÏÍÝ[ÙtĪ윑Ò×%qÏ]ÓÆ+W¢ûѧ“T<¶ÔçÊ/ƒô8„wÞ¸2]:ÎeO¹éÀd#©;x®ýåóŽŸ|ðÆuŽš¸1‘†‘¶.‰«¸ÈÐÑÒKo\—½Îûƒ:À:eR¼Ë¹¶.‰ nÙ¯qëë¢Z{þ⇬ã‹õu•\ÃÄÎEu¯G÷叫“Òkmñîm®¾X_—ÂU_ `ü`;®±}½n=é½ÄÕ0‹V[—ÂÕ\~<ºeK®±}ØByŽCš—ƺ.]_ˆ¾ç²Ú_ÚÌÒ|Õ¢¯Kàj/Žùô[\½,Ú¸ôdЍKá:;æ“[öÉÕyіL¡ú’9]] +×Ù1×'ï“ëý ì —J•l:ZÇuvÌõ©¾—1ïë9Sš\ùPÔuñ~ùäËãÿc—‹|¶—‡á¤¦ÒLrTu \ÕÉOnÙ?×­µ«^(u@Õ%póÉ-OÁõ. +‰vЌÕ%póÉ-[raß-Z‹ÁX]—x÷b멸n‰×f®^]×Ù1ŸEr”Ë&ûø*™ìе\cu)\o&˜4·õS/\²{ãb§®.…ëM2âúì-¹JÜú¡k¬.…ëØÓUt}Q7®D²­x”KW—Âçð±‰ËæÜM.ý9Õù±º®ê|²&±çڍO¿6ÝyÈJË5V—ÂUߜº7®ªÛŸûÞmz«Kájn³Q.›sˆçkãï·M­–k¬®!ž—Þ¶%ä]A ®qö¶ ©Ÿ,ŽÕ¥puÞ ë«™«õ¹F꒸r—Õ¹ìf¤jŸk¤.ƒ«´çZãÒmú¡ÿ VÑ×%qƒßxàjô +3àj¸ëQ2\ŸÊ(—Õû7䵘_ÚQ.}]—îý¬n¹:}l \Úº$®úêÓǹ¬²Þè!Ón”ØÔµ*–ïí¹Ê×ëMóU|–ïY +¶X¾ë“kz.ó떗ÉUüÓr•‹ä2/pÉe3aþ䚞Ëjb¹h®õ"¹Ä?-WºH.ólõA¹’ere0ðµü>ŽO®¸ö0ðÅ}Ïn‘\ðA¹ª Z~¯Ù\Åô²×å÷ÐÍULMÞá¾70¸@ªrÃ\ e’ºÒò{9ç*Š+[\Àa +%°ß{ZÀ‘›ì ù=Å¡­´e&=@~¯thG„â‚¥Âèo‘ßoXÀQã¸÷}ô•±mç˜Á8lc®Á9æ½Qæ#/Á9°Üè–ã‚s`™±Åš3‡}€²×ÀXcV@éK`3Ëڬހò9°ÊÜX@=€ÀXa6.@l`3°½9êT˜ËÍ"8á Kèmœ£ Jè„m®gƒú¡€S˜ „A:àª%ô¢©€ìڐ„>G˜ ‡bH}fv_ï\bAB/0Ò -Vè׋‘Ã]‡+_Ž V˜Ȑ+ A,0 +-V裥ÈaÜ媗#ˆ(Â-ôDˆ *âƒ-ôéBäpÝåB} Â(»‚-ôÇ¥€VÏP„#C̾:\ÕB")£œ· Å }ºÙHd.„Ð'‹TæB,Ýċu+_†pd8üƒ"âȇxà B8j¤—Â!Gl#´A `1Û¨«>BðÌØå +h)‚¸xí\Åú,(ÖCéÑg­¡% ÇÜ ýŽhIÂ1ó3?ú•‚+~€áï€d¼s°=z @KŽy>r’s˜y€Õø©bå™a÷H*:sˆH؇–(30Ê&ÐúyÖ9eˆιÈQDs‘ƒ²Ôā9£Ò7”AОQéI+Ò@½t>¥Ï)Mª’ζÚ&HšÔ¡9›!"li¥åڇkˆ´åhél¨vc! »ô™ ±¢g83âžö¼nų¢ †®@žâÌcˆñqCË`3Ĉ9qx@Ë`iˆf(Í4€ó`¦Ÿ¬Tԇ -g€M>kΩj-k€MœdY“½´¬6± +ÈcX]>±rz‹€5D'VFÔ +œéöÔ1GNÀY™8樼A:©ÔgB©œÇ Üϙ.H,8ޏÃtºc wàÊêd†kÍÁ…Tú‰:,c=càÔ4Æ €?R§é°ŒÖÛNÓaә_‚& :C¢Åqí±`»0ºk…äªé0‘qƒph­ ±÷UKó„ªY.´v†èuâ,øV­!zÕzìÓÝ ¹ð†èQ:j ›ÖÖãrfWŠØ ¬OKüñÍPË%¢¹-±±’.h­ ѓ&æV>¬­'BõÊXZ?Þ¹±´°öõ^†˜È,e \<1÷3–½í#×½{&ܸ¥rU¤s©ÍJÉ\"š LdöܹK0‘;¸)82‡i\o\´;¼•Ÿ'–‘P¬.t¬Â^¿¹1p1_uFÃÒÇàd}¡ãNSbé¥ +\EiW°/)áøf08Ô&[õ cœFwžÿf<[l2êR6W›qÀúßtŽ*OôÛø\‹+Š¿S;‹añcq€‰‹ÙaQt_zî¬ñ¹‘‘«ˆ¸ÿ¥ó/9k·6\"â—{”56¼OßYqYtØqœ=šÌñ…Ie˜>˜¹l:ìŒöªÿ짌ý¹K.ê4Li¯ƒ~/ÛÌæqµ¶\Mä¦ÜÝo·Û/¯oåe»}È,?mcÍå¢ÃœSþ#†KȵqÀe'‰³tŽ+¼Û9á +®ÃÌK_8.±´îBrvm¦(ˆ=$W›…ÄupÇU/«»Ð\¬•O_ºäj‚áÚ´.¹‚ÑzÜöžKdKÑxw gÑ q!Øý^ +—XŒÒ¸°DôÖ!‰kvKÄgиš…X!•kæø—°MäšÕ)¹/T®9½3eû‰Ê5c`OJš#sÍ6Ähi/t®™†1±ŒÁ5Ï#îí2¸fbÔ,%=pÍ`sM®ôT9×ÄÚÁÈdr‰<\)´ášRY©Ã\®éÀx™dl.FÚÏ$ŽËšk¢Éóā×þ9椰áòoŠü,M+.ß`ɧv\~UÑ&Yؒ˧ƒ¶Ê¶åòf—ŒoÍEΡö41qÏåcÚb™®î†Ë½,ڟ›pÂÕ +·¶øhß"7\o¶è®Ë’CW+Âé,—\ŽºìþІÆÕŠ'küâª-.¹ø©ÕªGw-qËe‘^Hݞ“‹Kæ–ʇìþ‹ë6øà"æÅÇ[ï¹ðÃõV^qÙññýw/·÷Æuê5ƒAÞm_}ÝÛ'ש۞¶wê~z|õy_ß\çŽ;žpØ>ÜËývûøúêý–“pÍPàÿÿÿârõä +äÿÿUÍM‚0à=§˜¥&¶öO KTؑ Ô4RPbZÐp{©+ÝÌbæ½oö*ØfÕ, àÇ êÕ±L2碂jhÆ·¶ +;´V÷½±rý˜t·V÷…@©'h¼Ãå˜yėQUäˆbꃈ +báòh9§ÚÍv=]F÷ +ŽÃgxÎöÖ^G RFˆB6t”~é 4ÎØ—©}5UÁ)ø×&óendstream +endobj +1689 0 obj +6288 +endobj +1690 0 obj<>>>endobj +1691 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +1692 0 obj +31 +endobj +1693 0 obj<>>>/Annots 13 0 R>>endobj +1694 0 obj<>stream +xڍUÉnÛ0½û+99@¥JòÞ[³Â@5v‚|¡%ÊfB‘*IÙp¿¾3”/I€Â€`R³¼7ófô§C„¿F ô†•«yçóÝ’æôã~8‚á¨ó¼›^°Œ_ΟѢqLAcô’Q˜Õ|-,X]¸-3*£W†•%7J¦j&éj#rþŽ‘P+ªÐ¦dNhøܚõ.K<>þ˜þ¦äq¯I–¡¹ÍvÖñ݋ëÇtv±¸„'LIAâ0ȈGý“(ô”Z·Ÿn6‚oO©‘ݰ±›Ÿ¢€ó¼¯œTÚ8¶”ε‘lǍ'C¾‹d0]qÃüKëØ¦ÖÌ‚Ûy' +#l =bz<ÜÃx€Œ“Q¡„8𠮿$aF=‹ðØÃ#‚]r® ç.1MË|õ8†Äáø(ì;öGh?‰ÂÞŒS³Úo±Ý2»ƒÙ¾ñ©Ñy9Ïú൞]pš*[jDZ°Ö1•3“ +kµ¬_…¤lz³á*×(7´¦¸ðª˜Ú¢.B •ºF"k;ùD~pÅÍ —|6/)Gm:nhlØêp¯C7¡¦d§¸;ȉ:i‰ÞÎï‚iš¢DYc¾dG†8`*¶"{OžõÒӀ?5¯1)  ÏàáòiPb7Œ“BÝoéÍ'x¸»ŽãÑdqù f(o|ÿ[ËV®¤Î^ÐlöýŠÞR†¯U5ÃKÄ\µP13vˆI«ÏRÚº"£²¶Â­Ápl!ŠZeÔ &…Û½[–ç°,[m^†ˆiiôÖeB‘jëf™•;pâÖ_Oì"Mop¸,?‚öﱚ`E¸x0¯ÌU•kj•óf,ßGŒì±ë™¬›ÙÎjët)þbîM»^t÷?á~}€¾èfµ1\9¹ƒ¨.ÞZ ÂA´¸<ÃKE` +DIm*n‘‡iŠ"aP"5Å™سRZG%kKjß®»~„S‹áotV—ìÞñg9îfaî,}Xäh¡ÍŠ)_L­½š -¥Þúñä^öK“%k³$cšÇ}¢E2Á)Œn Á› {Šx¼ÿú4Ázý†ßѪ?ŽÂ 2ÂÛ¸]¿:ÿ¨æ¢endstream +endobj +1695 0 obj +851 +endobj +1696 0 obj<>>>>>endobj +1697 0 obj<>stream +xڕ’±nà @w¾âÆt05˜ÚÎh;µÔ¡’[Sué‚Nic¬Üþ~%•²t@0Àݽ:ø" r Š2N=“V’Û^c 'à5åPÖ‚Ö ÷›7^Vp#?°@\ +62ïº—a„fx8§ÿø2V â¸@øÕÛ`Ýz{ Ɵ’xqÅÞ:ÀÎÛïTÏݕ§UúÓ¸}š AA·¸SP.¤‘-’cð««7ih‡h¿:,ž|Î՗ܶ¢q)¨ˆðî¹ée¼a|£q™Âò¶¼šgl<*·ªctdŒ—U< !¶4þÜÞLJ›½—ä‰ü…Ü‘3endstream +endobj +1698 0 obj +248 +endobj +1699 0 obj<>>>>>endobj +1700 0 obj<>stream +xڝUMÛ6½ûWÌqð*þŠw÷Ø ÚC².֛ô°ZÙìR¤JRrüïû†’?"-P0,™3ï͛7ÿGSšà3¥û͗”W£ëÑ»O4›ÐºÄ÷2›Óò~AëâfJw´òÚFm·ô|‘+zjÙ·š÷·ë¿¶ éTÂ»ùì>›Ièz§å;UGöT{×ê‚)K®'WÒÎí)î˜>ºªr–^¾üþçÞÞù·uh4½´ Ý-&ÙC‡Ã琕wÃՏÔpx¶ÌR=Ÿœ§+¨;²ìÜ‰ú˜¥þY–Ú©@µQۆ‹Äôuö~™Ñ‹5úé³Î½ ®Œò–¾i[¸}H¿ùYåOÏã®>>>>>endobj +1703 0 obj<>stream +xڍWÁnÛ8½ç+昱§“=6M³M‘b½µŠ½äBK”Íš"U’ŠÖýú}CJr¬&Å¢Ac™äpæ½7o”'s:Ç¿9½[ðOQŸÜä'oïþ ùåVWWقòò4ßJÊe±5VÛÍþMþÛ.i>OÛf‹ì’·}ø¶\‘ò´^–Ô6֐0$ké6ÊlèÞéŒ äƒ0¥p%Bkì ?..2·/ ¶°úŒ¬£ûå2ãÿh+_JÃIàêù»ì‚¯–õډ±Ö{*íOi<يŽ%²(ÇÏ^º'üª…i+Q„ÖIçÏâŽNiØäÛ¦±.¤`œ›‘ÿú¢ +g½­Âäæ”)m‡ëéDLÜï}uÖïÀáäKY)#=‰M_%U¨²jG‘D6øDE„/.Òw»öGõØ&(‹rµÚIªe©Ä$A¯~Ê3rÒ[ÝòÖT¬·|cØfôÀAà%憜€ g]€DÀÒò’¶Ìٞ)± ãuÁN®îsô´mMédéù\ØÚÖ#…ÈP­4ãщ}FßL¬Á"¦{žÃÖvw¥d„Fæ=C8XÒûÉ­…5Á±nD‹P´‡º¥)ܾIϵØ1°*€º-¶T[úeQ¸pCâÂê’A‹/ ñk±—(•ø€m¸FÆèÓò˜å,¤Ü ã9ýc…Êóåu[…<† Qêäº×-§ÒNAFùG@K’WÀ ·ô¤d‡Î(ÚˆD<’ ð¹õ¤ ÄP§¯yå ®±aZ0~½Z¹˜ÝÚáB馘DG•OªŒ²/lÝh$Sùvž‚°Ž­ÃH‡Ã±ÀPLȌɗ¶ + »IZ£“<¨DF·j#}x)Tþ°z&Ñ +ēPZ¬µBTµìÄ,Ď³Õä^®6Kîx0ÑÙåyvÍ«ŸÑ¹¯ZçGÚ+4Cªúv]«À.tä Xé]SPŠ¶è£ÂŽãŸfô9Ú²’P©äj‚Z£~´°¶¶^³)á’ñÌ2©Œ#ïÕÆ°][(Z-\ÍãlÂòñ´õmtˆQCoú4ØGbûnœ} am¡Ú©°eÑÖSãÞd+dw£äg}âhŽÂ6JöŽ+­Saÿ: 4.”þ÷3lô4§–Eèé¦ÑÏvÆv†SšPP¼} Áƒ^Üi·Æ@B•ûµRÎOGÌA…C[*7Ç8¯×z§4gûj­ýz² քO/šF́´ÒàÁÂ4„E$ªèÛL˜mÁ֜ YñDÉÒOƒêP2ã:¥5K„!fÂڔUò`S²Y ½ÞRå­l=쏝ñ²>%l.UU!nN¦æSO!ÖËã) + +y*gôO Opl©o8£^Qg”¹˜ ð;ŸMep#ŠLMôLcÖC`¦°¶¿Ð­jŸ`äÑæé<ãíûˆL/”²DO)‚44`õ[3’9r—c’U͕G\ÏèÓröçÃۋáqy{7|d@O¶øœ½Dõ8µ5Z•–¨yU8Մxöp }ž ¹ß`<²}[~?C’_ï—ø©hbœÉÅI¨ÎÒZ…Z4½úwšƒ>]ºùA·NôN°‹ïC°Evg†+4"4E+I0ïL˜Õu;ŒeŸ?Ëp«6Éÿñô}Ó¬,î oÎh•Zæ `a„nð:¶K‘ðb™:ë·BÖPêøÕ[Äu¯Äùł—çÿöëû»ڊ®ðvÛq;ùuÍúø‚e¡9ÀŒÏÍ®.âÁKþæòü:ã?"^üác~ò÷ÉœÜendstream +endobj +1704 0 obj +1365 +endobj +1705 0 obj<>>>>>endobj +1706 0 obj<>stream +xڅUÁrÓ0½ç+–\3‰›¤!ioPJ` Ã¥U–cQY2’\7Ï®$»© ÃäXÞÝ·ûÞ[å÷hsü,`³„Ó5ðjt±\Ãb»߬7›l »|²µR{aáÒÊ{aÝ«Ý/Œ[ÁbãfËu¶:ŽËcH ï~l¯í¤ó` +0ZÐWe¬€B*Oa®\’ƒ7À ŽE²˜*5WM.¾p¬ª•èÞS½8͖!¡0>ˆV ïg[Æï˜Íá3sÂ~˜ÎáR¸;úª¸ ~–«úRºÔ7äñ´ñ°ZXæ±ãÚˊ)0¯?€&Ì\…°B÷…qÂ\(7éc½\TȂåJÓÂÁ4À™†ÖJ<Á' ¦Õ}zG!õŒ[J@ûRTøy#²²(Ì£€³Õ<;£¸¯Â·ÆÞI½ÿŸv‘+æ6m4#@ŽÃ»ƒóÇP9ÖxS1/ñXÀ•x–C+} ãm +íóu„Ï`‡,FÀ +¦uà ßÔÁ$ Ï%O¼zl\R­ëË â¤$*ãjc2Žö#¡nк‘z £>†GœQRû8]p,çEyy0ï# ÎǺ馔Gó²GÀ·Hçù¤ž“GøÒ£ÙX…Q +¡Ba;°à]1ñ€;ä"ÍÔ±£$ʜ¨\ÕàN(Á}èoiÅÏÑÛRò²£ 9&Vo&"Ûg0Nùoˆ¼Å˜È|r´g7¯R¹ÎEag™r¤š¹—´¸Ñqë三Ä%–·"yì©!'Sˆ‘˸Q4‹Ä½!Úë#‡ž`3IŸ’ †$ÛÁߌV5ÊKºT"jƒÈ…ô%ëòàÈêÒ]'Óà(ñî¥)8Ä`£_z°B‘Ñ5äÕۜ +…ªxšÁ…ଷw`“`Ó¤½·âøÓþ& # П H›sL$ÎDÊc}{v‹ö6NÍ6ˆú‚IÕX1†F+t2q ioŽ‹ À;Ì}¸ÿðv{Å>Kb/–k8§ÿ˜Ëïo¯v0‹·þµ)|KØZ³·¬ª¨Ì¦¶wF™³Írþ?§ÕÙ<;‡ðö5=¿ß¾þc"PAendstream +endobj +1707 0 obj +824 +endobj +1708 0 obj<>>>>>endobj +1709 0 obj<>stream +xÚ-‹Á‚0DïûsÔC•ES¼ªÈͤÊúƒ±WÔߗ3s™7ybdc ›zŽ´šW+0CpnQää2)ëJ`°=¹uß ¯Nû«úƒ>±÷ÝËß§r#“<óm"K¶³¿í´í† (µ}ZzwBú©ð%\endstream +endobj +1710 0 obj +127 +endobj +1711 0 obj<>>>>>endobj +1712 0 obj<>stream +xÚu‘±nÂ0E÷|Å qã$$d ´TH¨p7Ç1ÄUp¨mú÷uš”Vª'ëwÏ{öG@ùC‘ÇH2ˆS°dÁú@ÐœÌ‘å)X=‚5«·íåv3cïMAi†&qNâg² ?;iPK+Œª¤…»%œÏ­Ü©Nckº£á§“4í\H짯™ìgdP y¯Š¦Y ’1íEU†›Ï˜Žà<"ßÃ?J'…Súø;ÀØ¥Q^\':}øçÉè°Ì’[%°“檄´w--ÚK-±Ví@ý©=Kwó—W®Z^µÒo®ú}-¸®±j¹µ?ñ‹ña}D‘ìÞ¤‹ˆò弿?±à5øM +‚Îendstream +endobj +1713 0 obj +282 +endobj +1714 0 obj<>>>>>endobj +1715 0 obj<>stream +xÚu‘ÁRƒ0E÷ùŠ·ÔH(RºT*Š3ŽñRx­8!±!èïK"Vq’UîɽwÞ; +Áx(¬b{ëŽ\3r‘m€FÀö£'ԁ5g…n¥iå²V`Î^IÞeàGV¬Ð8ÍA¨áñÍ´JΩ”Ë…°à½Ú9ÕE­¿¢¼xŠºc¬€ +õ{[ã5:¹å²Cƒ‹}R%%Ö®’QÀêJ—x°7£Šfî”÷ý`!þÍôÛÉļàɨ2Ü G$›ßi[nø )‘/"‹CʋùŒ ÔB4Œ!¦‘ŸXl[^e >>>>>endobj +1718 0 obj<>stream +xڅ‘_Oƒ0Åßù÷Q`‘?8G²dF„ú*½c(¬-êǗâ’e84}jίçܞ{´¸ã!zp@ÙZÔZ¥1è~T‚ˆ8P~³e3p„´nPÝÒwËûÞu|£­%2]‹ +˜€m–AŽÇ•žQ ç†I´–õÛ ¹(ø¿&9²KHõP8£ÒZüµëºÞô »¡:,ƒ&¤ÐLp&9<÷(ǏށW¨Í—F¡Fq[¿fÅ"7µþ´n§ÖwLT« +”u‰gò´Ÿóóý¬Ò1ñ܉z̓”‚ Ó$E·×ŸL"d²«$k[” +ž˜Xc lóÎ=÷ª½¹N “›û†Z/Ö7Ï¬Nendstream +endobj +1719 0 obj +277 +endobj +1720 0 obj<>>>>>endobj +1721 0 obj<>stream +xڍ’ÑNƒ0…ïyŠs©°vL6/•Åd‹(ø Veí,EŸÞ•²¹,1íÕ¾žsÚôÓ£ ÇEFv{ï1÷&É=è yuT¢ ¦È˛57FÈfDZäëƒ “uÇj~›¿{þ fcô„`% U§WXöGfF\_dîŠøÑP$M—ȸþoÏÐÐölû$‹¦+9Ñ8êBÛ(VºHke‰ð|0BÉL–XkÕÆ‰ÎA±×t¤ý…ÄÏ8bËô‡%†¨‘ïxÑ˕҈•¬Q˜1”qra1I Ô>FˆHÏ-_’>â·4C¦*óÍ4GªU­Ù~Ïu‹-“k¬oÏùó)±)±£p!ȾÀ*÷^¼_¥Ð¬endstream +endobj +1722 0 obj +290 +endobj +1723 0 obj<>>>>>endobj +1724 0 obj<>stream +xÚ}QOƒ0…ßùçQ@JØ£狉3cñá5£ÅFöïmÇ¢.KL“¦¹ùzî9çËcíaH#ðUï=ÞÝz…(Dр³,H¤1Šú†ÃÇ»£-Öb?’6·Å§¥c0æhÁ}¥Aä~0¨ºr°,j2•dЩ£Âlµ%±'w9¨Qùn³ åXê”CøqdNóõ@ú hþâ3p'›[ª&«|D®¤5éröuiÕòQ²ð;cƒ ”5žµšs%̹ åÒP?(]ê£KO'îÏÚMÙªJMÒ5tå?aK'¹ê{»ÌÒòºz’ãyiöë.û¯ò8m¡#sƒ§Â{ó¾-—€âendstream +endobj +1725 0 obj +278 +endobj +1726 0 obj<>>>>>endobj +1727 0 obj<>stream +xÚuËAE÷ýwÉb˜2Xz ÆºÑ¤e¦›Òˆ¿§3$6Rµª{îIê"ñ{4ì®=)êYԄ<¼“´Mµr_é»ó#m5+oœ­ÊSɵJ.J?ÜÐÞ ;[hë±VlÔ6××@ÿ06ÞØ#Ær:Afr¯¹4¶AŒ”¤ /?Xt3‰ýÕl‰¥;ø‡b»#«¢Ð|ÅTٛʃ" +ͨ•Ä¡HI85ãF­ƒøÏC)æâãuI&endstream +endobj +1728 0 obj +188 +endobj +1729 0 obj<>>>>>endobj +1730 0 obj<>stream +xڅ‘=OÃ0E÷üŠ;R‰„|Ñ´#º¡béb9ncÔØ©í4Ÿç:À€Êæœûλö)ʐҗ¡ÊQÌÁ»è¾ŽnÖKä)ê=òb™T˜W%êæªDŒw#TlTN<yÆÎêJ•È2ŸŠC,.ò*É}²n¥oYï#´|°VX´z„Ói¦C?Íl.3¯1¶’· $ƒí—숽>ô6À›^¨ÝÕnÐÅô:„.&ôŸ-«’:¦žÌ +ðXGÏÑ'Ü2¨yendstream +endobj +1731 0 obj +326 +endobj +1732 0 obj<>>>>>endobj +1733 0 obj<>stream +xڅ=oÂ0†wÿŠw ƒS;¤I!1PÉM\ua±À  |À9~~ãÒN•Zùn¹{Þ{ä “㓘&¾v-[höTÌ cèøI2FÐû`w=»Ò¸ÁRiÍ~=¶¥m°Lô‰ ðgÆ¿1UßmãþÄò¦wö‡ø2§3O¾ÍïTuw„ÁZq•o°¤úÃÒƒÏ ¥çe” "Ì|bYÎ ŽüMU¨úÃp3d¡¨?’i[K/¦»šÆŸà>ÉÓHø Œýh:šSˆÿ~½Òì•}’ö[>>>>>endobj +1736 0 obj<>stream +xÚu‘MSÂ0E÷ýw©‹Ö~Aa)Œ¸¥Œëˆ¶IMR˜þ{_hѧ‹Î´'÷¼ûò$ˆéIP¤È¦àM°(ƒ‡ÕiŒrt–G)¦E޲º› Ä»‘NªŒ +UÙûòƒðIâñpàÃ,-èEGÊ£´àGÖ:aP ËÜ ‹£>Ãiœ)L€a7„a¯ –Ûõ&ú‰×MÓ)Ɂ•4‚»ºÇYº#Z#¥Z0Uù)b„I6XY]“`Py9ìe}9Crës õ˜êáúV@ïɪ©¤Vp†)Û2#™£¡îIáë’2£™W¾â$ÅùÈG`G—åmï¨n¥VVVÂ0³?âÓéÀoíuæg£»Öþ βhzY±hZm˜é±’µ°ã*®Ú5;>>>>>endobj +1739 0 obj<>stream +xÚ}ÁNÃ0 †ïy +áÒdk:ŽÛظ€Thg³fU qÀË@¼= Eˆ²Oþ¿ÿ“ü&”ã(˜™¼û VV\l/AÕ`cbêº0`»³u ©“7ž,¹?GéxnŸ'|>á²*‹ù„¿~µ#ǘ|¤_îG+*tæ6ôî9R–Á²Ç§Á}[ÿ0ì“§Z74‘¬pÿâ¨›Ì P*›•6 U5õ®î—[ Ö»¦…6Ò²ƒ†cÏ‚ã#Ü"pÈ +™›²Öe.*“O³J (ÿ~cŝø¨â\™endstream +endobj +1740 0 obj +221 +endobj +1741 0 obj<>>>>>endobj +1742 0 obj<>stream +xÚu;Â0D{ŸbJ(lÇÄ¡‰"sC +æ#Áí±ù ÐV»ó´3»'Â@}1HŽ$ÅzOŠtÆ=p +U"ér¤R@­>" ¶qÚº¦­vž`,PQÀ¢„˘Rm«úx4¶¨®¨«Æù¶®q(á¶ë÷ßi}6(LYYS`u{Ãe¾@?ŸÆO›˜ 6‘ q,ÄG/¦ìé?Q*ÿ+NóÿÚLÛÍEoÌ÷ÙëN2ÎãßïRøl4hL†ÁH‘9¹Iaüendstream +endobj +1743 0 obj +207 +endobj +1744 0 obj<>>>>>endobj +1745 0 obj<>stream +xÚmŽA‚0D÷=Å,uQèÓâRAv&ê-&F ¶5^_W&æÏj^æå?A,G(eÊed{Ãòv R0ÃB¤R™„¹®´nPÏSˆvŠamîL€KʊÄ:¢ó¿8o+% $ʯ¦év­G}Ö=úyˆoë´Ÿoގ£óG;½ì#)xZrUˆ4¤*U¢¬‚øûÐÁ°ûw²8…endstream +endobj +1746 0 obj +157 +endobj +1747 0 obj<>>>>>endobj +1748 0 obj<>stream +xÚmŽA‚0E÷=Å_ê‚J¡¡²£‰; õ@KÀ b)‰ÞÞVŒ+3«ùÿeÞ<Cè†ADˆÔ7’I²9¦ˆBÈ1O©@"8¤ZePX3×v6zZË«9ó`°A yX¶Ý„rõ º'”žjÓUÚE}{ÛjL¿[n--J£ØtƒV¨^dÉ ìò]lÛ¯-ô¾„nÿÅwUèK–úà ə¼7@ùendstream +endobj +1749 0 obj +172 +endobj +1750 0 obj<>>>>>endobj +1751 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS042S072PIÑp rt QÐUp VÎO+)O,JU(ÊO/JÌÍM-*VðMÌ+MÌÑ ÉâÒéӅj42 ™š+€¹N@3‚KŠJ“KJ‹R‹AR®!\\R…$4endstream +endobj +1752 0 obj +126 +endobj +1753 0 obj<>>>>>endobj +1754 0 obj<>stream +xÚmŽA‚0E÷=Å_êlK\*‘ÄÆzm¨Á o º3³˜äÿ—yó 4 CƑ¤hîä ɦ܁SHd+bŽ4íª@„òi›É8;®å-pŒÍ\´€Q³°+;3¢e[óÆàÝË´*$ðJ+¯l£ GÝ÷pS§P\« öÕ ú§ˆGþuÐp^¤qþ÷‘‰ÐйãlŽ’œÉŸe<>>>>>endobj +1757 0 obj<>stream +xڕ•moÚ0Çßó)N4*Æy ê:©[Ûi/¶umú©òC3å9ɺîÓïl‡B(Y@ˆøþ>ÿ|¾;ÿ0 øa0sÕ7L‚ÁôÚæA°D‹ëyą †Õº¸ˆ¢oë2γÅp1?Ò6ʉC‰­”÷_ c¥à×F‹7qV*Ž0JæŽÃ<+J¹„qÆSqڒÃÎÓTÿæIuDŽ«CV¥¹^¬8âÁjåC ãq=i1:ÛÛúlfvw!WU*²²0 +SйO gâ³) óñÐ_Š"”±^CY®‚%çåçöØsTÛ¾ƒŽ˜å,J,î:Ä̛#•Q[Ž3·j}Êvç({ÎЈ*èM/ Ñ‚Gjò%”øßD‚ÁôtØS«;0 œË‡>á6=þpŽCh8­>g×éÓȬä×*ý!¤"¬í˜\Rb$Ϙ“›KɟQÏl\©7µV¤Æ!³ÝÄ79Ö +"—y#¨E?Jf£çޔZݙŸÛ›¹ž ñ­(+™ÕåµÉ_Õ^\S[:Sœ*ò݀“ƒ5Ûª;Õ´öÜh~€!ð(Âàdõj›¨kÆËXD¸u2\ýáé:9Ø4ßÄY˜T‘€w +„<¾oõ­Ö+!äuÁt —"L8†zïpa$?ÛËV-UÅåªû OªyIÌɶôr¥n —mCýÒu5Énâ zã&Á«ûüœÅe̓øo¯­66ç@Ûî7&õœÃbغ!#zÓ腢*âl{ÉuŒ«5á$QÌONá$%Ö,þkÞqðv÷âêíVŠ"O*õ¢|Ï(ÖñßÓëy]ÌrÁµ]`·×LàãýÍÜåËòI%ލÌW’§©|áYÅå`¢æM>>>/Annots 17 0 R>>endobj +1760 0 obj<>stream +xڕ’Ínƒ0„ï~Š9&R!^C€ÓrªJƒ{ËÅJ¨„Ôõõk¡M£V–V^Û³ßxíFàvb ¶d·’ÍÒ(„Üٝ(!_@¾Nr­±,êj*ßكdÜçVè¹°^¹Ñ<ð” VÕerWt$0{ÌR;§3íQ‹ÙžŽuj´~:6oÕ¡ÞL6Ó_‰D±LAѐý`òö̳Ş{‡¹f²µ¶ÒMçìª1!¾¯_"ihÍŒïñ?c™2õ¸i—(I/ò¼¥t{¿^¦î^²yµk>•ÑÈLµ7ª,µ©ñ¨'U¸ª‰^,øøW„±³Ü.‹ ïÍ3û{ùendstream +endobj +1761 0 obj +265 +endobj +1762 0 obj<>>>/Annots 21 0 R>>endobj +1763 0 obj<>stream +xڍTMÚ0½ó+FÛ TÚ&D­*х­ºjU +ìm/&È*q¨hÛß±@P‚=Ï3ofÞøw‡Á/…ah~IÞù²ì|xˆF°Ü %Œ"/„庛T{}Ïe"²ÇbõÜ}îõ–/é;ä žoOšo…³ˆk#£ÎM*KcÂJ¼ÑÇI!u Ɏ+x¿ºì7àðæƒîàõ>žÑ]ıÚV¹¥vˆ(5Š)òŠéʀhL½]àöDèD¥û2-¤±L—â¬Øñ1ÿ +þэ<¬cD=ŒàC X\3{qft„ÁOh[z¿æa.kS KͰÔf +“ + +IƵÉsq¤‡èîV’}¤¥æ˜«/–¿Á ûß&ÿ¡…xüf*}±^§Žû,vŚ‹²RRŸ µÏ!¶`m}ÈñWY³ è• B(t•$Bë>pµáiV)áÁÏã(w„R¦+\ÂJÀ¦¨äVqe©Ü‚ô[Rj fX\L;ß¹.§ÆÍaÔ¥±',»^«ú>E13ºÌZFûèÝd‚FmsÓ{‘¤›Th3wíq§x¾ÏZ¯w©L²j-à“ îí>7¦üúq‡ÕêQ”w} ×f!Œ3]´J˜1$¢sˆãã¢ÖÁµ.hxºÏúu1%¾2”VÐñ¼Ëq| +Ù¿MEöŽxH3qME£ú3·X-öÉ|ü°„Ü?Ͱ(6å+GmÏT±U<υÒðƒËŠgÆç€²³³Ï|³åÛ>>>/Annots 25 0 R>>endobj +1766 0 obj<>stream +xÚ¥VmoÚHþί龐èpl㬴•Ú&i#q)Gœo‘ÐÆ^ƒ+{í®×¥ý÷ÝµM Øp:@Àzžyæu÷ÇÈßø6L=ˆòѧptu€åC˜ Äó}Ã0GuYÝwiF—ôGM+ñ<~¾¸¿k´£Ñ×4‰~ªÈšj© A#´-­*-˕€K)Ƨ–iÌz l„PHùû÷Þ¼µ\ï> +V ˆ6„ËMUQóˆþ·] ’e$§Ï×o"1jg?òuS&*pÁ²$—šØ¾W ’+° 5àãZE<-EZ0)¹ G¦ab¾º¯åpfˆv©¶iØÀ)<ÁZŽ´ªÁvàÁ+´Ê»Ó°s¥&gf¡iÈðKû;b_Ãp!#Áh$Ɂ( ¢ü'åÆ ž¾‹*Ïå©ÀGxjvž%™4ÙÞ§w¿X@#€˜rŠ•ëæÙ¬¸—•ÓN[PGâ֊@–$‡Å·ÇðÇ©ƒŠÏå¨À½ñ‘*Ͷ|÷9ÊÔ e1lS±Qôºx>Û¶Ö¥2~xšÏõ£¶zÆP)”Cš+5ô¤ðÎrÒ¹Þ)ðÑúÝõßÔóu"–TԜUû å0òtëéZ©JlkªŠ0!g¸ˆ®‰ 풐4« øÆÔ¿)I)åµE„Á‹Ìt}ùë,KÙúMH¬ÆM\ÀGƒ 9A·È´—x¾†S é¦•ãtN*q+)´³ú ¤joç’Ñ;ÃæÐk{]·]Ðâ‚V@@µÁ^UŒLɋŸiŒ¹×-,……²Žû-Å픞6¾Xm8b¡HP{Òp«¦™Lpš²ª€ êËÐ f½~ÉS!0{¹Td(ÇÎÌ¥¨$Uµ-x|`”Ô¸‡‰4"j’ +¥1ûÃxû‹äeÖ{,þ•²(«c +ïd,Í‡ƒ³h°^,ÏÁïóéЋÞz‘h·ì+q¼0š£O½×æݩ*U7¦ÕbÈ´ëì +t•¶îgp)Å5Þ$Np¤Ó9`—´‹!ÎTW¬º/ :ß]&®R¡¯FOë#ùzµ4 cpu _¨P•ӄԙ€Ö¸¼:w’÷ЕuË1ìò0W‹ÞØhülwߛ£‘M¥‚Œ•ßµyÀµÏœA±=Ýîu÷×ZÁI×W՝eÚHY-†]s<]y˜½ºý5$'š?FQâ‡r5 ViŒäÑÉÕbyÿ®îîç·Í qÖÌBËöÀS19_—ïB˜Àç§Å#<‰Ø<@¼Xs’ç”Wða5É-¹sâÛæàÐu|yPÛm¢øï貘endstream +endobj +1767 0 obj +995 +endobj +1768 0 obj<>>>/Annots 35 0 R>>endobj +1769 0 obj<>stream +xÚµTmš@þòI/²î¢\s×PßjâyVñ›É…êúÒ(x°äúó;+,š;!^Òªfx^f˜× +Š_¦-ËCå»Wiô)8à­ñ†Ýn¼U5⯠…þ˜ý!á‘d_v+xöµæý®PÐ%mYó.l܁»Z¬ÚE|¾ÑîW"x w ™Ûó*”Pä#L¦€Ý4ñ°-<¥Áf’ê»üh#97­pw<"à Q‚͉KžL³äêB «Ãp2yñÜÁËó¤7u½áóø|©óÝÎz^ý ¸ühg9úrëG1ZÆóѨ…â ƒ e™(ò&mI}§¨PŸ*±$ƒerŒG~°éËpU¦rI‰¿á‹Ú¢vj“ž>§¨W—ÖÝæÑÈæî w³I/’Èß늚r«¬^å—‡S2|Ë/éùÍ{Ð:Z¦“þC‰óé°Ú ô$Úi¥dÓÞkˆsßhlÃXþ7"‡I´äÿƒàØ}ê!b–Šez#S‰{ ÕÂ1eÔ 64ÍæiLYÓΣÂ1U%¶Ó92YTµ¢ÍÆ2­+Y!Ý˃ZC„dËã" ->†AÌq'IänØßíù4-XT·BëÛ©;‚Á3¥]DüªC¾ÌJ÷¡nšä$iÆ9¸û8,Ý[–%Å cÌÀ-šF…ŽÉ­ËX +cYŒzÁ»|í'{¡ ¼Þ%Ö"­Ó0mÒ,¤9¦•a*Šn: e$?ìžRnò8ûaÒvÝÀMIù·Ë»ÊÉdfîrrbÞÎ %|Š‘œºN|)Šß‚óã«õòÁ2\Þp <¥ÁmseRb}Ü-%&9-âäp¬Iå„]Çû("e§ o0 Yù[™?me¿tÞh;©ÿÝ©Û÷@‡Î|2ƒY¸o~Äa…›È?xÓ$þ>Ý0Ae¡aËKØG W^ꟕ¿¹w@eendstream +endobj +1770 0 obj +726 +endobj +1771 0 obj<>>>/Annots 40 0 R>>endobj +1772 0 obj<>stream +xÚ¥VÛnâH}ç+JÚÇ6¾`±;“0¤LÂç-êØ xå ÓnOvÿ~ª/6 Á&Ò&q»NwŸ:uãçÀ-ðm{烯Ñàú[–Ñ-žïDÉ0®÷Õmҟ5­øóðùâ"úG!…¹¦áäSE¶TYM´Ñ¶Ô1é~¿æp)ÌøÖ2É‰ÃwœK”øu…w?ú8¦vöc㲨8Ä;ÂĆª¬YLŸ/¦üÕÛÖ9-x¥.X–@¾á¢?¾r¶ ŒX†'àë[ZÅ,Ýó´,„e LÃD¥Ûðœ ¢]Ó3l¼Û5°M|dV'ÀVà +…¶1î< eÈMÏœÀ,„~’˜<^ûEK¡DAcAx e¿(3úy:Ï0?ÍS¡OðTì|KÅG‡íˆâb¹m„prŽ™çâiŸf&ѝÌ\¦M~œR¯±AAr +›’Áòqc‰‡xŸg)Ñ'ã|HÔq0Q2†”׬ÐiÚ䁨9O娴ÚcþS©( ç¦@zøðtÿþ€!¤à;ÚÆbCÒ¬2౐O5RVÊž“^„u‘À˸β´Ø~ÐÄÒnâÆî=Ë!ÚE¦¼<³-˜ +h`ØM׸'Ÿ +MK:’Tîm]2:‹ý¨`ßÞ×êØÑ‚%%­€€Ì‘­tUÙ³òWš @¨ö6DZ›Wºa[²ªlÚÙXù»Ãc2<cY¿ä)ç¨ð»Ék(Ô̅iOªêµd QOc"kžTPPšÐ¤[Žù¿$ßg]ü´ˆ³:¡ð§ÐÄØ}9j¼½q·M÷±²ªEgÜZG[ …Ó!֝^ŒiïåV w˜CŽ^ô\na‰µ¡_g¤Øv3¸æGߨ=$€¤Yô˜øoæf¯óíœCÍÈ£úÀôDÄÞ, Ãè\_Âå2ûº!uÆ¡ñ.¯À­å/èÔFÄ“! û°­Wêèöá+Ä=Þs«Øt·ƒ¡t}$w÷xwÃ(᫹ ¯ïÊõƒwá¬w“@¦žeÚS¹è÷-Ð_¨0€ôõÿy¤I޾è£Üãe²#¬ÓÉ£“ë»y´^†‹‡h®gQ.¾>EóÕô‡éGq”PšžÍŸY’HQSF±EqÎҗšc{Sw·G֏çÈ9Þ_>¶ÛVÞ¶Â+ÔL:¡ásãՕ"šÝ­—óp-¯n¾ÏÂÕ<ºRq¢;¿e{àáà–Ѻ gß"ÁÍÓr«rÃ_ ŽÊ%+·Œä9eü EM23±säÛfçxq|á§´Û¾ÖåïÁoxøendstream +endobj +1773 0 obj +1006 +endobj +1774 0 obj<>>>/Annots 48 0 R>>endobj +1775 0 obj<>stream +xÚ­TYo›@~÷¯˜ò„#Ž]À©ÒŠÆ‡,¹Žkã7¤ˆâõQqeåïg×Ní˜:R-šef¾of¿á¥‡±ƒnò'Œ{?¼ž:Fà€·eLÛR4ð6"¼¿„ (èáwY\÷ÍI!H0_Ïfô½?½‘×C +b‰ù‚ù²œ€¦aÅ` M–0YŠ][¬8ìYݵ!5‡°ÌòYìFI˜nɎC‚P$úbĜÊ`Gü¾ßÿʽä*“Œe™Ž‘'óeîf³b5%;_¤ä¥$y!Át±xöÜÉóÓb´t½éÓü´5s瓵;Ig™®¶) Š’‘ÜPkúÕßøÂ—‡£3|o·äoíÇ{…ºNôK\/§ (•Kz:ÉV§/0œ{Uݧy‘1Q)ÉӒ†äßÕ;¦Pì ÔäE;õ̋åËÒ$'ð\ ÃtY9ûâ¾(2 Ú„ huì6*Y˺®˜<ߊp£<½ªZfÀÛGÍb¬±we]Õ,Œ+˜vþVîlƒ2blýþUDŒ-Åj15ÝT×0Q‹iԘ Å·Ç.’CÕÉM3´wýБÝZ7pkJù·uNh''ëm‡'ÇQôÛ9±>ň«ì1M¶‡Ø•^”º……lÁÑØÏ©2nÓ2/gº£EŽ¥8- ®¯Ñ.K¨¹™76ˆqš“×®ÞØMëùj|"7âpéŽ=áq½XÁ*ݯ%° éŽqLh?ƒ¤ ¢ã¿k&Ȗ†x fó-ÃÐ}0οzož«öendstream +endobj +1776 0 obj +595 +endobj +1777 0 obj<>>>/Annots 53 0 R>>endobj +1778 0 obj<>stream +xڍ”[oÚ0ÇßùGÚ LÅØÎ]L“ØZúԍ•ô ©òÙraN²®ß~vœMM"âó÷9?Ÿ‹ÿŒ`ù#àP0l’Ñ4[z@ð·Òb;²ÁÇAyȗ‚óï‡"ÊÒ|3ÞL&þ/­5µvjad*íSÎv\[1xµ‘íèo…Ê&—Fn¯ï(- -“çL/Ü´ôÐzÔþZû\ÀÇz×f2oíë†fZˆ]™ð´ÈµÂB”‚`9’ÜÑÇjTJD<"MX-ßò<QSYîüFXfõøz¼ӕj ۈ±12€bùWpX÷ˆ)ö®Õ”zoÔUy̚ÏR ¦GÅYº*¾*JÅ÷­L~rÙj;D)0!Ø+ºÎkº¶äÊ«Õ=¼šÒ!ºýŒ«L–\BÙr¡mI¯ƒ +uoFO=a¯§¨ª‘uÎU'Ûº.ŽDSŸ1l¥Y%Ž!áI&^åyD¬à!¼DÅŠ=¯O¬ ùÑ6â!ºØ­wÿXrˆ/؇( â2äðIÎÔ í?÷ŒÂÙ§¸ÓsÖKóžQíŽÚüºw„ÐuA'“çÃoç¹7%kÎaçY§]HÝXõ&VáWZóëhéÅNETRrÂ\„¡¦lÊÝÎ¥È:Æ#–j˜ qÐqNqn ÊOª¸çÅbä ¨œòAƒ9⁉߭¶ïÅ –*PƒarÞÃhX‡`¬˜ÈÛã×õ8[ºu-§„RéÜ".ª.ÍÛÇÅ҇)|}Z­am‹&Èv‚% 9<°´d±ò+÷Ú0u(¾2ú¦cJêJA½:)?Fÿø Ýéendstream +endobj +1779 0 obj +623 +endobj +1780 0 obj<>>>/Annots 56 0 R>>endobj +1781 0 obj<>stream +xÚ¥UÛnÛ0 }ÏWØKÚ.ªåÄvŒnz5îÓ: ª#;|Éd{Ý0ìßGZJ“8q7`I`DäÑá)Òßürûô‹óÁe48½ %èñƒ€ù-†q³ªîd}•‰ª’Õãðñè(új y›ô¡©4^Bët¹áQEM.´p‡M1ÇK¡áøø8¶†£³½Hã±!»Ði“Ë¢® ÂÎ ú/0bÖBð³÷£ùZV±V«Z•yn¢ÃLÅËãþ&SD{H4ÅÈ. Áu˜ ZÂü˜¸}‹v'>îܠۜN¬84xܞÀ²UׯhÕÍJL“ÔP—@Ù1-VÖ(´?Ù_T;T¶VÝ¢ªÞ$}âÛzÝ˺хMùúTTaßd>>>/Annots 59 0 R>>endobj +1784 0 obj<>stream +xÚ}“QoÚ0…ßùG&Á4Ò8„hÓ$ZÚ>Mb¾åÅK drlf;°þûÙ:Vɑu¿œ{|}ò»Gڇ '(›Þ]Þ»}Ì@Rä+[IÒ4HWý²Ýê'fflE[nŠ~1ä¿<:òèp#‡>kºf¾";#rԑB”ªðÉ1¶DÂ`ò^‹¬«bðå¢O{©3­Ú×G äÔ*ñ>¦ØÊZ¦`$̆¡òÊö­M-¨©¥:ÕgL—ªÞ:èt–‹]C9™éc͌îꍭòö¤BÉ©Öò²ÖÐF*V¡ §¹ÅAä\hc¡ÒVn **ìkÎñ“Aî˜Ú«Ú&Pô[ÝRÎ_lÕlž4mv”·¬€®œFË J‹uæám¶¼ó‚?Ô¢ämÅðÕMçÖ-ÁæÛ›«~³= bUôo®œÿ£. +qó—3¿–‘%c˜r-ð÷ ´yw qËâÉmG±õÑ u×ê7Ëwà3 Á„ÙUú h@ÆY0>Ãï.̨5ÎcG£ÿ~‹{—¦Ý_‡0÷Ò§äýS _'GE%ˆ³±Ìl1}Ì1Äýó|‰¥\™=U s%׊6UÄw*lZœèÐ}9L£°;ñ£Ôy=19ŽúGï/]7¶endstream +endobj +1785 0 obj +483 +endobj +1786 0 obj<>>>/Annots 64 0 R>>endobj +1787 0 obj<>stream +xڍ•[o›0Çßó)Žº—´j\lîê6)[—jR»v }«Tyà¤l:›öíç ’B"øÏ9?Ÿ¿',ñÃ`{òg“OÑäbö!Z‰Ï÷‘Q2ë×òšUw¯UZäOÓ§ÓÓè§V:Z9s-äHåcI×L¯ZšE‚™"/+ˆ_(‡3©KØBÁ€‡¶2§;ïÈaïHó +ò:{.ÔÛåq±ôd”Ïœ™wžN/{{²m=çë:cyUj… KEè +ó3âë7"©Á!F¾° _±2æ©ò!W¾D Y"êÛÓÃ58P»–‡ˆðM Ä—œÁr@,m£&ŽpK­Òç8D8¾OþÙ\^)endstream +endobj +1788 0 obj +742 +endobj +1789 0 obj<>>>/Annots 66 0 R>>endobj +1790 0 obj<>stream +xڍS˒Ú0¼óS› ¤‚°üv6IÉ.{Ù¤˜àĶI„ÍßG²dðòJŠ*ÀL3ÝÓÓó«‡ÁQ/ ‘ ^«²÷9í& àÒµª„Q„BH³þjW‹'*§Dˆ=ãÙ²¿ Òëì0p¯± A6ÔTHlÑŶ«„„Õ–px«1ª„_äèbkÎÊZ.÷g´žg:ùfWÒJ +ƒcHä)úÈhkAƒŒ"ÕAýü@ŊçµÌY¥+iÏA޲æð6{?Vè@5Š7F¸rS˜_ãD ÚUÿÄtã±oåZC€í fÊF\CшK·L$ƒ,uAþè¯Rv‚rô͎^âknÐ5M÷C»³•;^YËۙôºCë7Ô,¯$å­ÞÚnW= {"€ê2̀qhCcÚô¿-žŸ_wîC¾†Š»t «É8Ù#ôjÀÔÖyaæ0 ’çÕH•?Åa%°V㐃Né«Ù鋄\´ù÷”ËJBÅ$ÐՖ)/N—{q¬ÇRÖÅÕK{“W«b—Qø gé7´ýtrs§'hnÍ꼿 FÝæýgöÞM J5Ëë8õþî֍Ï)…q!ØYà±Í°zëØ–„êÃ<&Â'x¾nhqŒÍ"´Ø9å¿)ocp‘+ԧےa|¤>cs,›UdiÞ5y?×Ôð/đý¼Ñh[Ùa¢¼¼Ø8þ0OR—Åts¶–{¢ÎwÊن“²¤\ÀWRíH¡»±Â0rñ÷#_5nžgøÞû u·¤)endstream +endobj +1791 0 obj +607 +endobj +1792 0 obj<>>>>>endobj +1793 0 obj<>stream +xÚ¥TËnÛ0¼û+éÅ.`F”eÉAÚ¢i󸤅›(‡¾0e±•H—¤âæï»”(Gq-PØlîpwfgµ¿FüP˜Åî›Õ£Oéèðühi‘8IH i>ʍ¹àv¹<]W“Iú£ƒEl:Hä`7†­y àÈCês(i,d%ÓðÖa0D²ØO?„m´–ëÕäøIÉÙ¬Ëz¢×MÍ¥5b”: b¤4 “ŽXr zDI‚)ðø”›L‹JºÈY: +H€-Ù=®. Z zމ@cW4 HšÃõ3à†dæÑa“`€n{y~sÇaN½¯³e×ÖhÙ¥%Éjª‹¿=Šü…jà<ûgª-úYª͎bïÓ·–¾Õ½gqܵyȘåõFi¦ï¡4Ö2!…\·jÐìî\ièG¦K8þzsyù¸ÆÄ£@ƤTn9T*c–ç.M®¸<î§k†zUÉî8Òé ’gio $>÷&<°\sk°T¦6÷½k;2´¾AùÎLHªÚÞ¡4§Ë_Ç[õžž?pšû?Ke¬»@<¼gü]5`JÕT9š[+ìÅjÜÈJȟ«Éc†¬p$îÏp r%94Æù%lÇÓ¡ZŽÂ€±J£!Q¯±ÌŠ n›¢è¦xÀ–ɶ¢ªZMw\oµ°–K<³%p–•(£VíOÁ«~Ùij߬ÞT/n¡7BfU“sxçòº)?ìí£ýõÔ-£M~ü:Žò:SÀ{ +{jŸ_vÿQśëªí6ç¢ß‹a ó$ꀧW'ç)LáóÍò®Ua·Î÷¥VkÍêšk_˜lXåRLÝÍi¶›i¹£ˆÆ„v«ê©W¸ ¾þãï¿endstream +endobj +1794 0 obj +661 +endobj +1795 0 obj<>>>/Annots 69 0 R>>endobj +1796 0 obj<>stream +xÚ¥UÛnÛ0 }ÏWØKÚ.ªåød+ÐûӀ,qŸÖaPÙÑàK&Ùë†aÿ>ʖs±ãnÀÀŽÈCò™o +~)ø6Œ=X¥ƒ›ppù0êC¡Æó}âA¸®Ê­zäÅLЬàR=ŸÏί5Ö©±#×"ŽÆ>)óZkÁÄ(mZ;B{­B µHpÒõjÃ$œŸŸoÉÙ´k<®Ý]˸LyV¨á¥1ñ0¢_Ói A'”øhâ;®VRl ‘gZs,ba5vù#8¢]t`d›LÀ¶ˆ ’ÃâXûö Úv<´Ü£«²:†œ«9¸ÔdÐdYÑ«‚Tôfy%†"]¶Ò‡­2)ÙOòږnÝ?Ó®Ð'iï«îx¦es^”235oÒÒMöꒇY™.‘jÉ°y+`ߙHØ2ᤷ¯­îè›Ô‰Ò{'FCˆyá ªÐL +äµ ¾ãC@ó•UN|]Ô&/“5,9D’£´T"‹µƒl¤­éhÜ)/ž(@(ÈrHò,ÆZd蓯ûó¿ÿÁÒmÒ;EoD¶JÊ5‡wº—úA6W­Áj1Y1=%Å^}iªÑ˜iìS·Ž„×‡¡à=tzø¿þEÏÇA®Àª›r€úÕ:D¹DC”¬)Ðú#7ZxqÑqø©ß?‰Ïfaõ“lÛt ~÷ތçp¨¼3ýÔ 4pœœ‚¯'¥úÍ~ÝëS(.ŠW°{} +Ô ðÎïÀ72†ÃÅàÒ£‘Û„)Å«}Û܀;±2)šjí©Ê_`üQÛÏ ê%p7¿~a·O³,ò¨xa¸ºf2%KSÝÿ,+Y¢Ž´åÈ·­W¶‡ã;؁ +1vM?þ§óâQendstream +endobj +1797 0 obj +663 +endobj +1798 0 obj<>>>/Annots 75 0 R>>endobj +1799 0 obj<>stream +xڍ•]oÚ0†ïùGÚ T#Ä %DÝ&±ªJÝ֕TÚRå&xrlf;tüûÙù`|„´ErÎëó>>>vþt¸æ‡ÀÙœu¾FÁ,@”šÈ(œDI7Î×êóå IqÎô¢»èõ¢ß¥vXjû—®3´Ú'…—¤ŒºVAU‰Wâ–pa5&„\gÜè±4Yô®NŒ|¿ÌõHt.¹*ãC@¨ö• X Ê5‘ è¤Ì ̸ä”–yl’ç¬É Q±¤kM¯×tbt¶:5TdÉ +¸ÁR!ùˆš¨©ª+ç;žõ7 +ÊI/Û"Í!g÷~òýö‡ð •‚g„kØ`Iñ 3nwi1_­ILSjî,c̹ÐðB€‰k2B^¨~Ìï~-ºS¾dT­½b³Ð+’8•².Ý5fì¸.çLÒTK³›© æ[ÈH&ä°R"¦Ø+Õ«¬¡Ð¯z+rÀfÞ²ïÓ¿8[³³}üò˜å O–v°Û±Õ—£®nhòg«~ÖpQϺ:9ŽÓže·´ÏÐÐ{Wí“ßÌ~XÿÚ«í$ÎÍnL˜V0:®ãš{Å>}<ÞÚxîØ¨3=ǯ æöÊ9ÒË%ìŸgÏ /¡)EBù²îFÇ00‹©-QÐâéVžWeö±èÊS²ÿÕa¹éï6ì3xÃÀ´ü 5è»!öŽH#ƒwé9áŽÁGãÝè,C ú^†[¢[|o¸[xC½]†šó½s-÷úá4ß`6®Ú©B[KT}¬n'³úpýô0‡¹Hõ«½¤XJœeD*ø†yŽ™ÍÛGÞúçډþȾòM›Ùèù€)ÉÏÎ?=èùendstream +endobj +1800 0 obj +654 +endobj +1801 0 obj<>>>/Annots 81 0 R>>endobj +1802 0 obj<>stream +xڕ•ËnÛ0E÷þЁ»I‹I=‘¶@ÚÄÙ´@+; Ó² +Yrõ@ûùR¤œJ~Õdˆ¼˜9s‡CÿšP°ñKÁgÀ=H¶“/Ñävõ!ZãŽçûăhu•´»ú[\¤ER®²"]^-¯¯£ŸØéĖkGŠ_ë8Ý® ¡ÞdTGÚÄÜÈ]\¤6 ‡—+o9.½5p#[Œ¹¼¾%弋{_¥íVMÝ)\ T*¨-+°˜ß¡•ѐCàòƒ¨“*Û5YYȝÇhb­é/Oà¨v1PÔóf㣰8 fÔ!¡V3Æ1ù^­±ýA¬ã6o¤ëÃp½Á{õ¾Iƒ)þ +l^ 1 +tÐù…pŸ×åhF¨>öø”ûøÜBÀ Õ/ywêú*…÷çœò¨Þr4]ÈaÔù¨w"¡­j(•iʐÔޘ¼­7'¨÷ž€ñ€ðsóB՛ÌáòîÔÜñ’:C`0/#x§{À©‹ÃÛ„¬; +`(/X¨ËÍ0Œ£ÝÎ}†,H3Ü@]&/÷ó,øúú¼€E¹n~Çxý>WeZÅÛ­¨jømœË¨eøæ3ûÔMèøFWîk?~Lþ»fOendstream +endobj +1803 0 obj +665 +endobj +1804 0 obj<>>>/Annots 87 0 R>>endobj +1805 0 obj<>stream +xڕ”ËNë0†÷yŠ‘Ø´Ò‰kǹU $. ›ƒ$ìº1‰›9Iãlrµ¤€Eû÷Ìçßÿ³`ý ¾yÓÒºL¬E´@²Ñ3~ ’l–¶»æ/«òH´Ív=[ÏçÉs§t;¥íaäåcÃrÞÍbXö“éÒ¼ÔEfæôÁ(ü"³Q¬ç§é)í2\ó&•ÅNu5!d¨âw°n¯œÁFrÞ„–µ%ÛTµR«-S°e/ž8¯Œ¬N™âš„Z½±r'&w}RT©h3g†l1ÔDÛó=/öB„ÐqÁÁF§}‹9‡ ÑÔF°J,Œ°>yó!æópc §,!¤ˆô€Ø4Ş^æðá§Y·çü5ß°V¨Áû/ †¡&*’Ðli¢$îKöX}­?ðîÆØ±ªÒ:+ªü( }DG ÇóG&1֟rDºÛŽ28>AÞÈ@`Œ&4è/nøñ£ ºK>NßÅK´ü` ü)B¬ä§£8Ì·ˆÂ¾l¿ÛáüÃE”€ Ww1ÄõF½2ÉáNÖ¹deÉe·¬j™0ymâø`6 ih†\ì!sÍMÝ Ú{ë?.Ì?`endstream +endobj +1806 0 obj +456 +endobj +1807 0 obj<>>>/Annots 93 0 R>>endobj +1808 0 obj<>stream +xڍ”ÛŽÚ0†ïyŠ‘zUclÇ9i«J´»ìM+m—ìÒ* +&¤ÊæÐöñ;Nl@$„²çgæ›ùGþ=a@ñÃÀã`»瓯ád¾ €yn1âzq!ÜLãv_ŠdYI¹ž®g³ðW/½Ðr(JøVG‰ì£ä¬Ïò§L7*†WŒ˜XÞ3<¾7ðQý¶˜m={”³í>ã¢JÚ\MÝ+`L)‚i,îõLF¤4,`Äà xý(ë¸J÷MZ*òN(¡8Ã×ë3Õ&ò±v€59%* «1 |bk5x{¢î+4ž£¦{0}vx]‘/ÜI0!¨›ª›S5%lqVä2UÆÝÜ©G‘3®¶ìlnÊè¾-å´Û||_LÿÓ®…l±ÞË8ݦr3Ò,¹èûÓ¿(ßgíCZÄY»‘ðYÌMf²ûr¶~#Û8Ø¿‡3!äv–có÷¬ñJJXdu90•iŸ:g\ÖäàۄéCÖÛt¦¯8ÎZýÏAé ×£ÜFmÖ_F ú¾Ú]‘ùª³ %©.©±t­OÐ ev€x*âr“ÉU +滸žƒã·0 ë½ˬ­wW!¸«–Ú@Ø6?œ.BÒ{!žåu7lÛ;tžƒ`âö 罫¦:qc˜o¾ôõFYœªGè÷àu± Á‚oo/+X•Ûæo„ïÇKU&U”粪áGT´Q¦òZŒ»`yœ^z$„§²va;Ðóø9ùP¢¥endstream +endobj +1809 0 obj +569 +endobj +1810 0 obj<>>>/Annots 99 0 R>>endobj +1811 0 obj<>stream +xÚ¥•]oÚ0†ïùGÝ TÍóºMêV¨*mZWRiHUœ)q˜í¨ûù;Nœ”–@‘&Eâ×ç<çËüQ°ðCÁñõ7)GŸ£ÑÅb4€(Å?ˆÑzœÔ[ù5æÙ S«ñj2‰~·:·ÕM=‹¸Z÷ ㌵»Ì̦MŸ<håQÁ¹áµH¸ç ©¸Tlbç<.Ùjr¹çÑqZ£W"«KƕlPªÔ +E×AËÕ©´ˆÎ( о¾f2ùVå×;óhd SÒ/÷7à†¨öÐPÔ÷ˆ ¶…‹`°ÛÔ!3£¶m?«›Üº†ÏÓ 5Aè ´ÆAƒmè×P¥ ðwQ%qÁȘ–®×ɘzó9Ñ®o*tÏT-¸Is†®®oR Û*çŠ PÄ ë\c3€T¢NðhË>XÃWeн³g~°;Œ1¢7tƒŽ!­D“C¹eIžælÝenw“ ¹^)X³4ç(®—®UL’Ü}_Þþ„Õxγ"—›Õd縬I•«Z±õápçãr[“w9OŠzÍàƒŽù¢‹‡l>½š™êÇ«;uyü !ä¸ ÏæGxQ³Tœ™±üëÉ…`lÕû:6îKÆàªÕÞPÓÚøÔ p-!tðhж³_éE»½LT×,ë¢o·Awa¨Îø£¡Žë€CË84P§÷Ð$dªG˜ó¤Zç<;Ê@CŸ8=„;{ ¢#=bQÔØçÇl_i‡à8~_…ƒç‰M‡!p\J¼žÀ¥aÿt1Oö¿Tb§ û¶.¡i#œc ¼°¹*®ï¯LáËÃÝ–Uªžb¼ŽîD•‰¸,™ð-æu\h›Sjû0 ìæöw-ýÊ¥n÷w0pýa~ŒþïþõÆendstream +endobj +1812 0 obj +684 +endobj +1813 0 obj<>>>/Annots 105 0 R>>endobj +1814 0 obj<>stream +xڍ–moÚ0Çßó)NÝZ7vžÕmR·oÚ©kÒ“PdJê$êöígÇ!@‚ûûîçó݅÷C¼1¸LÙà[8¸›ø€]caq\9.‡‹jSiUiÙ`g4O®Ñá°'wÕÏÐñ’t[7Ú1Ԗ`Ìùr¯:°ç ³a Ž!†ÄiÍy)Ä$­ŠõIâÈÎÕ¦é4'ÐK )/&¨«ã€iad7–xàÙgäåáëÖQя=ÝM<]@b2ˆb<ÔCìñõa¨îò¸üˆÄÔ~áùŠGYFyÏ«¢TzaâÀÈ%Fÿô³\KœY-°°ÎÃÏÁ͓>Ðendstream +endobj +1815 0 obj +728 +endobj +1816 0 obj<>>>/Annots 108 0 R>>endobj +1817 0 obj<>stream +xÚ}S]o›0}çW\i/‰´8(Pu›”¥aJ×–зH‘GœÔ“1̘u?v [¡Y\ßsÏ9Ø÷þt0¸úÁà‡æÍ çsæÌ“KÀdG £…&ySÕ·¤V+)K¹›ì¦Óì‡E9»pQ`59Q›uá²MzØÒ°ªÚ׊¨¦Þ+ƒÑ)ì¢øŒÂ¯’vÓ«Œï[¦ UµÍ€q§Z T4•D±R@^ +E˜`âê‰×B°NS F ª\Ó:—¬2Ý/ ”Fަó4i­žÖ[DA™ç”ô€`}Q¶©nה ` +žç-×À ö‘g¼hæýÃ×¾ÍöE‹Û/î“Ûõ2댟Çê7)*>z½ï˜Èys ðÁÊÜ,èéSï¢{áë–ûqõvBèm€e0¸šñ~ÚR + ^—°Ê¹z2̂ͲùbðbW£ ˆ|ä·‡­š^žàuWz1þ7FK"rÊoÊï]¯œ•‹bý/‚¿Ñ@Ðm[S­Òû—+Úz±J&TÂ8í, ÙæIÜÚ¿ðPÛn¿Þ,’ f°|L·°-ê™H +©,O’zÜj¸#¢!ܰΰÂ,ò\Sxf+ÀXwª;:7ú,¾9N:8`endstream +endobj +1818 0 obj +484 +endobj +1819 0 obj<>>>/Annots 113 0 R>>endobj +1820 0 obj<>stream +xڕUÛn›@}÷WŒÔ—¤Š7ìrWªJnGyˆJcò)ښµCË­ ôò÷e—ÄÁØ¡ !`3ggÎ~Î(XxRðجóÙ§xv¾ úo0âù>ñ NNÖmUßrùãKÕ¤eQ?œ<œžÆß5ÖÑØ¹kGaïk¾:jAh‚ŒêDiѨ¾¡ FSWUò¸I3ñØÀ{¼?àap`F(Úü±Ôß¿Wå V0_=œ^ì­Ç¶5å…ܶ¹(šZ#\ T! ̙¯݃††”ø˜__Šz-Ó®†Š\Å3‹XØóçËÝ58¢]Ë# (s0³ðV +X€©ojÐÌsÕõÝ Ï1ô\ÅÁ ™b]ìxuÙ;^ñ“€(ºÕghJÈqä8ClMf¨Ñ# 5/Ÿêéì n„!F¿ å ‡ úG.%ÿûoäLçÝ¡òvŒÇ9/ *QŽH[úß<sOæÙ¡Gð"a; t›ïDÓʸWˆÚ•žVïëf¯Ëb“¥ë¦†MÙ 9¸3êVû}/õAçèiœt⫇#îÕIঞÕ%<ñ"ÉDðªJ‹­bzEæ;(xŽ1„ôûß&öñ¬ÅDeÜ^×ÕžWÙA{—ë¬M|P‹;Wòôqà;ƒGåR/ǎì/Fìpߟ†¨ÄCÙäÅñú„ã€1>{e¬0Á+WBÀ‡µ'ujԋzÎÿ-æ>ÓÒ åvÅîüŠI¢yör­0âöŨ§öÕx5ËTóýç"gеgPW})…Èy´>õBö˜cc£0$§p¸̈́0'$vÏÀ¶Ý7[`XNaqYÛ°Ÿð|˜ Î)õ1·Ç˜6†Ë»Å2†9|¾V°*7ÍoŽÉr+yž YÃ-/Zž©¼sÊ<˜ûÌ:â(Žï`úáØ¦#_gÿL Cendstream +endobj +1821 0 obj +718 +endobj +1822 0 obj<>>>/Annots 118 0 R>>endobj +1823 0 obj<>stream +xڍ•ÛnÚ@†ïyŠ•ªÁÆë³•¦mJԋ¨ip®Jm`·>е´oßÙõšÛ 2^ÏٙñŸ?,W~çIïSØ»˜@=—hq=¸.Îæå&¿c"çß6E”¥ùìl6„¿*±]‰GŽAl)~ÈيWVm4iå)J iÂ;Ô ~·ï9ž ˜¯™€s&VÃÆÐ<Ð'¤eò˜UŽêeD-~,àü\?7\¶þ“eUØc±*žy¥p€R©ð] 12½ê×"©¡%zÀÛ×<Ÿ‹HՖ/aÏ &~{º¿ÛGµc¸ÄjÚèÎ4ðRp˜vˆ©gªÕ¦ëÈóV­vÐÖxŽd°SR`"—ò®¸Â5‡¼QºÌxÁ¢T^f)‡L@’¡;rÛÆ,'cWêì +Ö£Õ¦íìg6ZŸ¸€lY#b @±Þ‚ý;ƍ þéÜJ½—ÛÑõÝÍ<†M†UŠÈEÖæ¬ÇxmcœÌ«ÔåñZßVàWé¾çE)R]Ýuùȶu«ÒVIç/ûÿšðÎþiô€œ ­û‡L tiÏUÄ|ÃçÑ2•.â%–mGõJX©Gsý”%üê™Å%ïoç„ET‡([(Ÿï§™ZøŠƒˆ¥ðÄñ'Žù’2.¢MÌ¡ˆI’aó$OÆÝÝ×¥ÈÈù3,Ö|ùþì|ùËt¹of¾‹Òy\.8|)º'²þؘr¥œ‰¯ÇN7]vŒßa¸GÕXB vÂMwµIW0kBÌ­'Þ:l— +Ž·çÎÏ᛼?a´O9‡qœg­æ£ºŸp¾lþð}¨¯ãª™j±‚ÝöQ¯ãñbQÁÖeÝË7‰S£®ìôîh†ŽæyÛ CP)k©èÁ›mÕŸº jÓ¶ð÷0€†<…á†'dÀ´bÕ–åM¦<…à–‰ß,´ý]L|½#J=ôêZz@\ߏ'!ŒàóÃݦٲxa8fîD¶,I¸Èᖥ%‹¥ß5]y¦ÿ¶-oY~€ÞŒC£3ò½÷ñ‚=endstream +endobj +1824 0 obj +794 +endobj +1825 0 obj<>>>>>endobj +1826 0 obj<>stream +xڕ•mOÛ0Çß÷SœØ@Ôä©I*¦ilÀÄ´I Â;$”¦N”8™ãˆñíwg'-´ -©Tž¿Ï¿œïÎG6Xø³!pÀõ!)FߢÑéÕì¢-~0¢ùaÒTõÌ„ºÊrþpøpt=¥g”ã‰Å>>>/Annots 121 0 R>>endobj +1829 0 obj<>stream +xÚuQo …ßùçQ“•B¡->:g—,[â,{ó…U4YZÙ¨f°áËÔ@nrážóÜ/ÂÁÂáU¼Ý@î5ɛ¸„Þ…ŸJqZ@o'­µ˜÷£›ê²Ô„Q„±ðX֏±AU +ª0 T¤¦G=ÿÍû=òF‚óD)e ”îô9.Ì¡³ý“{ßL6ӛ¸Zřǥ¢å- KÀ*‘î­/cýFx6ãqé½óç—ny£Rü² uðý[ÓÃzÞhdX¼­Z´nwü6ÞbåÝޛa°~ċ9œLM3^TÈê‚E¡¬â“”ìʺ_Éå-dendstream +endobj +1830 0 obj +238 +endobj +1831 0 obj<>>>/Annots 127 0 R>>endobj +1832 0 obj<>stream +xڕT]oÚ0}çW\i/0c'vœ¨Ó$֕íeƒT}Aª¢`h¦„0;lýù³cÂG+Á¾Ç÷ž{΍ÿô`ý!À=ðH‹Þ—¸7šD@8Ä+ 8GÄË~ºÛªY¢*!ïòR‰E1Ä¿-–ZìaD öA%ka£"ôˆMô·Ì–&¦·FáÉÜfãIÖ;O|ÔÿƒÛN9ß·Çr½+ĦRÁ€ƒ ˜"¢ërKªA‰â:…Þþ*T*³m••¹{a­Éþgö h¨ÑL' +°að0ò@ +˜Ÿ{˜ïў5ź—:~Ìp`Ä5¡{¬™±ÈòŠŸX@UR$T%¤Ft…'6޽™g>Éó 4 œQGb{m/ÆßÀê|vPš¾û¶ •nQmEš­2±l7‹Îš}ÿ’Ûüìt}È6i¾[ +ødxŒlRôüùhâN `{Þn/@]ÏØRáÊ Ï…€q®ÊŽ·ÄمÌ×À#ý°‹Üºu„—k8èmÎÑco~nŦ±æd½¢h_D‡U§"v+WêjE:¼^q˜‰dù]…¼ÈÄÃxßn>fˆ]£Òð}—iö"ru‘‹OÈ+¨çŸ7¢áÒ~;—G™U¢-L7mÿæò¨Pó2kçôûÍÜêì¬8рքÔ,ڒtYŒ&asÛzPº{b6žÄ0„»‡éæåªú—è{e*˵LŠBH?’Í.ÉMÒ¡99ä¾pyPNuâA¹ëûWï?Ñ^®endstream +endobj +1833 0 obj +576 +endobj +1834 0 obj<>>>/Annots 133 0 R>>endobj +1835 0 obj<>stream +xڕ”mo›0ÇßçSœ´7锸6Ϩۤ¬M·IÝÖª¾©¡Ä¤L( K‹<jþމq4OðêjøBȰCÀGho +@Û©CsfÁ9ÌRYœY‘ÕöÂ`ށÈÀ£hK}“jwµôbÇ~bŽÙîÜuZHÞ´®3¡ç {›Œ O3ëKIë”5VkR¹óì"@3|Å?.I ª:Þ ˜Ô鯾Aixÿå>yá©d1™q´-–a½’õ²4ÀogyēÁO7æ<ìx2ìËGЬKv}×k¼²Õ°:±HEqº%ç—·^m3fàtêÁvÌnC˜VGE\î#A÷¢Øˆ(˸ð=ÊwQª‚N՛Sר¦¿å©G¦¯f)í6Xö¯Ñ_‰Õ" endstream +endobj +1836 0 obj +715 +endobj +1837 0 obj<>>>>>endobj +1838 0 obj<>stream +xڍTÛnÚ@}ç+FªTA¯ñU¤•Hš‡V¥à<• +YfWøÒ][Iåß;»k'Ád9{æò·CÁÀ/ׄ¡QÒ¹:—¨ Á-Žë‚U7*s1 EÁøŒ…«[ü1¾è.z½àv°´ÃÀ6ˆ%îD¸aÚj€_Mª£•©ˆ7)[I;SƒxǓÈÓ%WÇË>àS¿ámå–#‰åV’¾úiÑÐ5³1ߔ K ¡6P*®Gl¤ïê»Õ ‰¡>%.FÀã/LD<΋8K¥å&èÄ@}Ÿÿf_ÁòmS— ê†‹ôMƒ˜ÀÌ[ÀÔv0­F›ÝC«BY=[r° Sˁ +)f*¾blhAœ… † W°æYBN³µ|㼕­F·°U-ÏÔ:ëJ4hŽ!ÏâT²Dz!ÈâJÚeT”¬fŽÀìs×Álof®Ð­:¿4ŠeúZäC6iÕ&ud‹;ºG(d)ˆ2Š˜}4àÛ͏ dç'G;°ÑEr|‚ŸžÆšMW %JʊC !rÅ똭ö[ã8³›‡0ÉwG‡ú]œF»rÅàJÒ»ÔAÉöScX¯XÆÃÙÝÅ)µ,‡—5P}ä68|}ýЄÖ{¢mÈë˜yüÀvâ—G}ówӁrú:÷ÛxÇ`q¤BrwÁûz éz½r~<Økg󬱥]©|c¤´ƒ«êÂDò¸eñf[T–‹‹ƒ´- uÿS%Ju­PÿuŽëSÆ¿aŽj¿ž"Ýv3€§ÆÉ“n5¯êgj:àà˜jLfãIø|7Ã<[÷!Îë”g& 㾇iîdˆô¸¦qnv,תw‘åW»ågç?#»æ&endstream +endobj +1839 0 obj +665 +endobj +1840 0 obj<>>>/Annots 139 0 R>>endobj +1841 0 obj<>stream +xڍ“QOÂ0Çßû)îq$Ðõ¶®ˆN_Œ¸ÍøÂË…`6†D?¾­é¦ˆ[H›&×Þýÿ¿´×w‚ÀÌ@…«ŠÜäÄO¦€ò91Òòµ—)³²©Gù¹Ë £ÌÚí’ÞÛDÒ*ˆ•.(!³šòõü„¢s‰¸I5.«Ó¡I‹æ¨ô¼¬µô–£^ÃX²ÖEDEŸ%s–ËyÁJ_‚ý‚x:¨ý J¤ØAò©¢%½ž"UÅz±ûTe3Ș§’K8åY/K |=Ë«ÞՃRº…¹”õÆÃ]™¹ófLÒÈE½mbÓÑ$œ5Ç7Åù•\RøIì 2¦ÜŠÜ¦³$‡ Ì_dõæøQh ]ouQUJ7ðXìOEi5'¶p"f #f·8ýóžÉ³%ÆKendstream +endobj +1842 0 obj +320 +endobj +1843 0 obj<>>>>>endobj +1844 0 obj<>stream +xڕUmOÛ0þÞ_qÒ¤©jâ4ol 6­+áÓ2!Ó:M¦¼tŽ#˜ÿ}g;%M[–J•c?w÷ÜÝãËï |FÌòÞyØ;¾õ!ŒñÄó}âA8ïÏêe5e•äbÊÙ|’>ò¬ŠúÑ`þ2Ž1ºq”ÁmÅܜZ0nmj¼ÕE•. +>Wç¸M-l¢vï„Þ¾“p€«£–t=«0K˜€ƒ¥öö–/2‰'YŽF&‘3±¨s^ÈÊ \ T!ÝmߔbR:¦ÄG¸}Á«™H—2- urö,ba;þýM?ƒ Úµ²|™mUïÒb–Õs§ŠÛ±qJ’­AÒzEYnΕ,-øIÇÈ{nÍ£fÜ.`‚Ùk¼Y´¡¯'_ó˜;ô# cûgۀ²;‡$Í8D­ö\ëè‘!GðÞp‰¦YkÆO3wo<€õõUÅàX'ºvpÚ$Lkž.ٜn„xêöÝÓ4_ˆõçJë.¾`Œæ3°‹tWfÏ­g#µ 3µ=ð\Ÿèi|1=» +aŸn'7pSÆòá՝ˆr!XžsQÁWVÔ,S.†ÊrèÛÖ¾‹ãøFÖ0—6cæ{ï/¾åendstream +endobj +1845 0 obj +700 +endobj +1846 0 obj<>>>/Annots 145 0 R>>endobj +1847 0 obj<>stream +xڕ“QOÂ0Çß÷)î(½­ëÊ#¢Ó#n3¾ð²@!˜aяïDāf[“kïþÿ_ÛÛ»‡ éA4¿³Ò»É¼A<T-hE>dóNj-ŒŠºêfoÞ]æI!©ä!¹çt%)¢&( eÍùn ƒXbã*J%—ÙnS'y½µn\Tµv¦ÝVC£‰ìàˆ:ºÍR6– VãÕ–>ûñ´±ë‹ ¡À#„O‡%¯AHÿN‘Ø|þ@ŸuY|:ðÈ ^c!à‘¼ºÕ֞¢œ‹vz—{DIÚ?ݘŒwµ6 §#%œ´Æžb²ú´EÝN1ˆMÓ^èkˆŒP,r›Œâ ú0~™¤V‹íGî,L\µtyYZWÃc¾Þåkö¹°ù’ CŸ§” +@þò7<{_íÅÆendstream +endobj +1848 0 obj +318 +endobj +1849 0 obj<>>>/Annots 151 0 R>>endobj +1850 0 obj<>stream +xڕ•ÛnÚ@†ïyŠ‘*U¤Çk|BI+‘4‡‹V¥@ԋRE–YÀ•Oݵ•TUß½³'ठ‘µ÷ßÙoÿ™üê0ñKÀ³`äB˜ô.½³›1kœq=Ïpa±ê‡eÎg/(ûÆ¢‚ÞÑ`EÙ²¿<9YüT+lµb蘆-VÜó`CÕ¬ c=i®Ly´IéJÌãkbþ]Äë&ß?ðGƒÚBhýÈu9bªâh<î9ËÄȌ¼EL| uJm9îžZޕ­ñÁà˜–ò-’d2¾$[l)( Œ < +—q`†µÇ.†}-¬R·ÀJD5Òfu5Ê äY” +H¤+YÜ(é3ð1ZÏÅ^M+Õ­Ö¾ä†m•¯3Z”,ՙQY/òÚUiA K—aH9à>QÆ2ftf[-cD±4¢)¾Š£¯ìáÒ8žÓ0ZGtU·0ØOƒn²ë§ ÉãÎ~¥a\®(\¼3ÔØ~¨Ufí/·Y§q”Òó–VðRóú#Jÿð¹ÌÕ .­º„Û€U1óè‰Æü»OÆÖúÃ0§ãfD‡‚·{­¦;Æ:c°ì à=˜çÒ ¸ÐG0Äw4Úl =szªî}'ŸF7< +®šãúTڠѕ'ƒ]†ËߘYSÊ>!CóH;³hN)Lbž5j–è2Äp,¼|ËWŽcUƒ55ÛÀnÕ¹.*÷.á*Î8­ +£u7_¬ÑÛüëvìgêý’ÞhòØ ¨‚/9M¤"°|R¾“@S¾a†—¶ß"ZA,´Â©@FcrÔ +„ý_Œ*©tÆ6BöÓ ïÉôT>tæŠG-y àìÆ×éD,a²'[òlr³€!\ÝOç0ÏÖÅc€ÿ¦,Û° I(ãð9HË !‡bÝг̣}Úöl¬©sFúØ_{ÿ¡uq¾endstream +endobj +1851 0 obj +778 +endobj +1852 0 obj<>>>>>endobj +1853 0 obj<>stream +xڕT[oÚ0~çWiÒmq㐫è&µëía“¤ÚØ*7˜‰æ8j§iÿ}¶Oh!„Ë BÆç;ǟÏåûÕ¢`©…ž§¿qÖºŠZç·!P¢©²x¾O<ˆ&í¸\CVH.¾‰TòAúÂçŸ=ît¢Ÿèá G×µˆ£= +–p´ZVF›b¸2/Ò$çmWÇÔ"Áž[ôñ£0çNÔî¬æku Ä3&àdiÂý§ëœç‰œ;ý­‡özø–K‘”Ïe(ÕjY„ªû˜ŽJƒhH‰¯B¨ãk^Ä"]Êt‘kËMÔ²ˆ¥jòú3¼'Ph×òˆ Ô¥*¨m©­à0jÓ0TïB´Ý ˆ»†6Åu*~®æà„¶f¡2jx™è†W4〇B +Î2 xÖEQ²ŸªxÄ:š*¢¨"AŸb™°x ,&L²WЇøy®Šy4?ƒÞÉÏ­:û¤_^fO*‹‹)<ý–¼8š¤ãªÀG“4èÆz¿ul/ 0—C.K‘Wýºê=öjmÍYòœìƒZ'ë©ß +|@EVTژ!•+E¤Xò8¦j7+Í6ûs7±›–-ç;¥è]šÇórÂáB³;Ç dö±&µ¿i.·Ecžæ¼ß ioÚU--aû€3Î&›:tSת…ò= ¡ý£î@ÙÿœZaî͵c­ gðIT¸;Æt!`ÜÖ9€`õM6à¢zÑ7Üó4™ÉÊrzŠe_‹ðgKšØÑS†z¥øë®t7¸ø¬8l?é/vI°ÒpÛÏvÐv=¼¼  Ÿ#-¦ò™©)ˆE"X–qQÀ–—l®Ctµg×· +¸Ž>êy!ŠÂÞ!P‚ðµõý},endstream +endobj +1854 0 obj +652 +endobj +1855 0 obj<>>>/Annots 157 0 R>>endobj +1856 0 obj<>stream +xڕ’Ao‚@…ïüŠ9b"ËÎ + ­-í¥©š^¼] ˆ]4íÏïl³•ˆm›Ì2ûÞ·Ãût8=‘€‘„EåÜ原ŒÈWôEÆÈäK7S +&eSòç!w8ãtÐ,h–ôÑ Ã‹¡‚˜³È%dFó¢_¯ÁO@´.a@­ä²8운höJO˺Qsw>¸jK"kQ†L^³äÖÒbY¯!é.Ø ÄËNm{0B†GAÃâ· ZÒ¿S¤ªX>Ñ«t/‹ „G–Ño„€ÿM2Û|«²iIºšî°?"'.úa(X`««1íægÉxכ½:ŸG—ÂOb›.¢˜¼Hä>$9x0}›eÕ«ýW¡Ìt½ÖEU)ÝÀs±=¥ÑôÌA/ü2ýAdö»†ö®¯Î“bŕendstream +endobj +1857 0 obj +317 +endobj +1858 0 obj<>>>/Annots 160 0 R>>endobj +1859 0 obj<>stream +xڍ”ÛŽÚ0†ïyŠÑö*9q궕h {ՊBèRåM&àʱ©m }ûÚ9°ÙdYU +ñŒÿùf2ãß\óó Ûœu>EárÞ¢ÔXƓ‰3†(鯧£Ú <£Üuw½^ô«p ·ÁÈuBë¶Ud…Õ…Yiô½RCp¥!> o­1y®3mʟMv½ûVŒ (dÖ¨O’«Â‚çUaÆÃŽ‚r´}@H0%'¦A倓 ›ê_PŒ5¼Ê£á¥bT ]ÿá€Èj@(-$&@¹‘Pšh1©lÙÇ· „'p¡ŒÁ#‚0IµFnöôÐlü…˜³xžÌ«)Ô2ÚØ0A“UF¹L¥ÈòäRÁ˜¸P¾¿²ªwVÖ=©yNŽ‘«6x>oW›Ÿ›ÅúÇbݬ'ò3•‚gÈ5œ‰¤ä‘a¿Qÿ¶r‘å7SÛ¦pB%ƚžÑ–Z_O’zÇtmÚ<™Ò6BPC¨JvJ÷áÎV„Ùç»Fß luªÎ[ü!ّݜž7”Çì” ¼·\C»8‡9jŽUmâŠÏwÿúò€çýq{7ˆ0gJX‡EÔq×\(vñì²~°/àûY3˜ŽœQùÂ`c¿ÜC½ }ÿ:n¨WD©‹IÕ°/†›yµx^0s‚[Ý2` •Gê矰 •#lÕÓ°´e†ËiɺF0œ·Éz¾Œ`¶½a#R}!a%Å^’,C©à+á'¬æÀóÇ0˜ø®=8Û­Ð`¹/ß8&ûï ”ëendstream +endobj +1860 0 obj +594 +endobj +1861 0 obj<>>>>>endobj +1862 0 obj<>stream +xڍTMoÛ0 ½çWØ%Çrü‰º¥v(%îiÙAudGƒmy²Òµûõ£,;n]gm†øH>>Rü=!`ãŸ@àÀ҇¤˜|Ž'‹ëHqŠ?,âý49Vůêšçl7ÝÍfñ/t pîٖ«·5͘±ÚµF‡´QTÂ{mÅKb[áËÐ’âwI öa€…§?^*@X¦»ÙÅ BË¥Éy)³cÁJU„„hDàZ ë¤1$"V€ðzÅêDòJqQjËU<±-;›¯à†ˆöH`¡Ž¶9Ûr@2؎€‰YË턑>OèFz·¥çiží˜²;9zM’†^|` õ¢‰bj%y™pùÊ*$•ÐE°þ_‡ù˜ñ­uôH {7tLLF¸×ü/‘6T;‚]¼„»GÅê×>F|3á=*|?9®Õ7LeÙÎM×=Í~;4P œA”5ïFÞ žu¬wžZgÇt0j}¨' Çá)8d¬d’¢h@GZ©Ôƍvn‹{*ª¨†Ñö\²D ŒÐúõuÅžr¶Çu/t‰r"Ç>ÁI‹øf½ú¶†gå=—¢Ô¯§w9;/ÏÕ-ªüìbyÇË$?î|Ô-ôa> –ÇpïèMӉóÃñüŸ¯8<“ÿ´¢š1i³›öQؖKç54­6—×1ÌáËíz [‘ª?çp-E&iQ0Yà -4×!æÚs8ö¹þ»¸ÈB󤼠}+ß'ÿk6Œwendstream +endobj +1863 0 obj +594 +endobj +1864 0 obj<>>>/Annots 163 0 R>>endobj +1865 0 obj<>stream +xÚ}S]o›0}çW\i/É´$ê6)[šjR7¥¼åÅ'ñ6³MÓþûÙ@Ú$„ d÷ÜsÎý௃™ ƒÚ;-œo‰3^ÎGìL$Œ"7„$¤U©6ŠÊí`;&PЀFä´QdO›(‚YôpË ¸Òˆ„cB¹ÓKògÁ²íð®£àû ɚêJrÕÄÀø$6æP +Æ5• è…´’’r •¡ç¤  $œ6ك_›ÇÇK°]m³àǘ‚ŠgtÇ8ÍÜ^s ªRÉJÍ¿”83Øí㻨lŠ«•k¯D)‘2¢iG¦‚¬5¢L^)¤ý~­!Wõí ­éê Aõª4-NÃð]¯vHò¼¿ÆûR”yï?0žæUFá³-tl÷ðõjÜ×Ó?[ [ÕÝÿáuá_༑ýûS +ó\ ¸Oä"³ïöÀöX?Øð‘gJ/`:q'íK±ý®ðrç[ç£Sˌ—ªWf^G!ßZ}Sp†Ïq™g$j%[[­Ö§z¼]cµ‰˜Êç÷ÝêR—ÓÖ}€ i€Ã¦§‹õ|™À¾oV1Äb§DRXI±—¤(¨Tð“ðŠä–u„½F‘‡lâdj?¾5‡ní·éÁ“ó)Wendstream +endobj +1866 0 obj +484 +endobj +1867 0 obj<>>>>>endobj +1868 0 obj<>stream +xڅ‘Ënà E÷þŠY& SC±1K§Iºª”ÚÎ.ä×­_¬öó ±ڨ!±˜9÷Üy 0Dö``n¨º`S7{˜Ay¶„1”@ù´z6fÜ´CõÚôõiuZ¯ËR†q„¨ZÔÒumR_ËT=u²7Ú«bÀØ©0qš°ï”ƒ0LjY[[ÞJ]©f4Íлή "ÙW/W~4µtL¹5òJëL@I(~€ uc/4CüOz¶&‹5CÑÎdq^àK®s\”Ç>×\šIõzìâ՟¿tv¢Ûë€ )!kõàóM—|»Uîmól_BwÇCÅp6ïÂ>젆Z‰®“JÃè'Ñ:‹Ð)CF¢ß6OE©_OÌç­<Ÿ…,‘Gendstream +endobj +1869 0 obj +293 +endobj +1870 0 obj<>>>>>endobj +1871 0 obj<>stream +xڅ’=oƒ0†w~ōɵƒÃHóÑ©R +dËbQ‡¤å«Æ¨ýùõÕ5QÔ +Äp÷Ükû1b +‹ߢösïam'"ˆ ŒéV'U¼f‡ù<sw”’€#µïe©°kkœ»Z¢Ë¡VéÝT”âe8ã3qM!DckËkÕúܙsÛ`g“{$ vËÓ'}¾´tÈcä&m2­ »3ŽËŽ´â?éK4›¢E@þKfSòR/ºx:©©2ƒnú‹°Qâ͙u6_²îª[Á™RT}ëü.'¿x¥±[h&Û|XíwdíÑ|J»±nK-ëZéže3È +#|œôûñ,ñ:"wÿ{%/Þ7Ä*Ž›endstream +endobj +1872 0 obj +291 +endobj +1873 0 obj<>>>>>endobj +1874 0 obj<>stream +xڅ‘?oà ÅwŠ“ÁÔPlÌè&q§J©M¶,(!®+ÿ+Øj?~A8VU©î~ï¼û0Dö``8µÁ“r˜¸ØNÂJ@œWoã8l%u^«ælŽ«ãz-Þ=K=Æ¢Ž=Y)×µ5J}-ÓÕÔªn4^ÆN…‰Ó„„ý¦„9FÌÚÚòV™“®‡±î;×ى B‘}ørÏ@SKǔ[#¯´Î´‚ò˜P7öJ3ÄïÒ³5Y¬Šþs&‹ó_£ã¢<öÑjœtgæÀ®!ÞüùGg÷%Û¡¹ ¸T +²Æô>ßtÉ7±‹å~жÈr!lûÊþ2~Jû°½î+-ÛVi/²›dã,B§ ‰î,Ÿ2ŠR¿¡ϋy ¾¸Ž“jendstream +endobj +1875 0 obj +295 +endobj +1876 0 obj<>>>>>endobj +1877 0 obj<>stream +xڅ’=oƒ0†w~ōɵÁñHóÑ©R +d˂R‡¦â«6¨ýù=׀Ú(Jb¸{îµý˜Á‡BÛ÷T{¹÷°“@ägìÄB1䯋·¾ïÖUkÔqq\.ówGqGù ¸¥¦(•íbsWKt9Ԫ鍛Š€R;E™ñ™øKYˆJŒÅòF™“¾tý¥mlg›{$ ¸åù“>_!q‰An“hÙ ˜q»ìD‹@Þ¥Çh6G‹€ü—Ìæäž¤Žº¸ŒœÔTõƒnÌ(l’xuæ_íWQwÕµàL)H*Ó:¿«Ù¯½RéÚ¤É.և}Y{î? ÜØ^·¥.êZiÏE3•ðí¤/؏ÿ˜ÙCtDnþx%/Þ7ø“ŽÐendstream +endobj +1878 0 obj +291 +endobj +1879 0 obj<>>>>>endobj +1880 0 obj<>stream +xڅ‘Ënƒ0E÷|Å,“®í KšGW•RpvÙ êÐT`¨1j?¿¶ ¨ú%/fνcßy `{p +›ª6¸ÁÝ!ÂA\l'æÅ žW/ÆôÛN)Y™óê¼^‹WÏ1υFÌq§¡¬¥ëÚc¾–ézl¥2ƒWE@ˆSê4!åß)‘” nmmy'‡J_{sí”ëìE€¶^®üXb鈥ÖÈ+­3-¡ø¦ÌiŽÒ?éɚ.Öáÿœéâ¼Às¬S\,|¬¹4£VÃØâ͟¿töeÛ7·RBÖ Ï7YòíRS?h—g!lOÇŠîbÞKû°£îj]¶­Ô<–j,g:eÈ)þeñŒ3”øíěi)OÁ';„endstream +endobj +1881 0 obj +292 +endobj +1882 0 obj<>>>>>endobj +1883 0 obj<>stream +xڅ’Ërƒ †÷>ÅY& ©P”°´5éª3©’]6Œ!6oEœöñ E6ÓËè¸8ç;?ðák€!²†ÛĽe܉àfÇ3gÛIC ˆÓê٘>SewR =®Žëµxñ õ`Gˆ:ð0ÈJ¹®­Qêk©®ÆFµfðS1`ì¦0q3!aß)a޳±¶œ©¡Ô—Þ\ºÖu¶"ˆPdw½|ò KÇ”Û ?i“ hÅ0¡nٙfˆÿIOÑd‰f(ú/™,É <{tQ{¯¹2£n‡IØ,ñêÌ_:ÛwÙôõµàB)Hë¡ó~7‹_w«Ü/”åéN@÷‡}Ew6oÒnl¯»J˦Qz€Gَ²v¡› ùôŸPW¢[GÑo¿‚½•§àNې>endstream +endobj +1884 0 obj +293 +endobj +1885 0 obj<>>>>>endobj +1886 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6ftë¤S¥Ô&[”7•ÿcµ¿ «¢VH w¿÷Þ}D°;8…ûŽmô £»­ÂAž\'å¥ _WoÖ…n´Õ‡Õa½–ïc‹Œ˜Çö£ªµïºc¡–›zjugÇ J€¯"ÔkbÊS"‚ îl]¹Ðãќ{î;ßÙÈ#ìÞ¼\å°ÌÑ Î((3£¡ºSæÇ^hŽÄŸôlMkŽðÎtq^àKªs\L$!ÕRÛÉtãØ%Ä«?ÿèl¾T;4×WZCތ}È7[òMÝNET”ùVB û]U²ŸÊ=lgúÚ¨¶Õf„gÕMªñ±WƜâÛ{gœ¡,,'M杼Dß}n˜endstream +endobj +1887 0 obj +290 +endobj +1888 0 obj<>>>>>endobj +1889 0 obj<>stream +xڅ’?oƒ0Åw>ōɀ‹]ƒñHÒ©R +Ζ‡¦â_ ¨ýøõÕµQÔ +‹áî÷žíw~÷(ö£pá*ïAyw[ T€:ÙN$‰@W¯ãاmÙuÄ«Ãz­ÞÈè‡áî‡¢ÒØµ5Î]-1ÕÔèvœ*JQEj|&~SQI‰°¶¶¼ÑCiÎýxîZì¤Ê H`O½ü²'à±¥C.­‘SZgFC~f·½Ð‚È?éٚ-ւÿ9³Åy/¹Îqqº\3=N¦æÀ.!^ÝùG'ý,š¾¾8×’zè\¾ñ’/NUº6Y²UàÃã~—CޝƏÂlgºÊM£ÍÏE;5Zø¨ôûÎ?аÄ)%±È­§`§òâ}eíZendstream +endobj +1890 0 obj +295 +endobj +1891 0 obj<>>>>>endobj +1892 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6ft§S¥Ôv¶,(%n*ÿ+`µ¿ «¢VH w¿÷Þ}D°;8…ûŽ]ôPGw[„C}r”s”Býºz³v,´ôauX¯ë÷@±@Å FÌS{#å»®ÆX¨åº™:Õ[T âU„zMLùoÊCDĝ­+o”9êóhÏCï;Ea„Ý“—«|–9:aÂ¥s¦ T7`ÊüØ Í‘ø“ž­ébÍþϙ.Î | uŽ‹‰$„Z*;éÞ́]B¼úóNñ%»±½¸R +òÖ !ßlÉ7u+aЦ̷5Äð¸ßUP 'û)ÝÃvzh´ì:¥ <Ë~’­·ˆ½2æß\;ã ea7)ŸWò}GΏendstream +endobj +1893 0 obj +290 +endobj +1894 0 obj<>>>>>endobj +1895 0 obj<>stream +xڅ’?oƒ0Åw>ōÉŎÁ0Ò&tª”Ù²X©CRñ¯¶Qûñë« j£(ÃÝï½³ŸýáíG`ã:´Þcå=ä)ÕÑvb΃ª·Åɘ!oF}Ú/öËeõî(æ(? +†ÔN‹Zb×ÖsµLÕc+;£*BPE(j|ÊÿR‘”ÜÚÚòZêƒ:æÜwØÙT^„vËó¯x–X:b©5rJëLAI(oÀ”áØ Íƒô.=YÓٚáÎtvžáK¨S\,\¨…4£êôØ%Ä«3ÿêl¾D;4×—RBÖèÞå›Ìù╦nкÈò +|xÚmK(û£ùvc[Õ×J´­T^D7Š-|Túœþä'Xb+Þ|öJ^½o¿Žñendstream +endobj +1896 0 obj +291 +endobj +1897 0 obj<>>>>>endobj +1898 0 obj<>stream +xڅ‘Ënà E÷þŠY& S Ø˜¥Û>>>>>endobj +1901 0 obj<>stream +xڅ’Ko„ …÷þŠ»œYHAÑ¥í>>>>>endobj +1904 0 obj<>stream +xڅ‘?oà ÅwŠ“ÁÔPlìÑ­“L•R›lYPJ\WþWÀj?~A8VE©î~ï¼û 0Dö``8uÁ¶`ül; c(þ¶z7fÜIS#+£š¾>®Žë5ÿð4õtGˆ:ú E-]×Ö(õµ\ÕS'{£½*Œ +§ ûK9g1kk˅Ô'Ռ¦z×Ùð B‘}úr•; ©¥cšY#¯´Î”„êL¨{¡ÊîÒ³5Y¬Šþs&‹ó_ã¢YìÃ-¥™T¯çÀ.!^ýùWgó-º±½¸’òV>ßtÉ7±«Íü ¢Ì·Bx>ì+¨†³ùöa{5ÔJtT^D?‰ÖY„N2Ý]?e¥~G Ï«y ~Ñë•endstream +endobj +1905 0 obj +296 +endobj +1906 0 obj<>>>>>endobj +1907 0 obj<>stream +xڅ’OSƒ0Åï|Š=¶"IiŽ(mOÎTHo½djŠ8ü3„яob(£ªÃa÷÷^6oy 0DöÁ°JÜ{j‚{Üm9`âl; c(ñ¼x1¦ß)“I£DÕ¨ãâ¸\ŠWÏRφq„¨cƒ,•ëÚ¥¾–êrlTk¯Šc§ÂÄiBÂ~RÂ#fmm9SÃIW½©ºÖu6"ˆPdŸ?ùèÚÒ1åÖÈ+­3­ ¸ꎽРñ?éɚÌÖ Eÿ9“Ùy†/ÑNqQûhseFÝS`—¯îü­³ùM__\(i=t>ßõœ¯[,÷eyºÂÃa_@ѝͻ´ƒíuWjÙ4Jð(ÛQÖÎ"tʐ‘¯üq¥•˜û…üò7ØÅ<Ÿb“Mendstream +endobj +1908 0 obj +296 +endobj +1909 0 obj<>>>>>endobj +1910 0 obj<>stream +xڅ‘?oƒ0Åw>ōɀk;ÃH›©R +dËb%¥â_QûñkˀڨieÉÃÝウ߽{°98…MçÆ{,¼‡4¡¸šNÈ9 +¡¸¬^µî÷R§•¬/§Õi½.ÞÈè1 QJÛ55Æ\-QåØÈVN!VE¨Õø”ÿ¤,Db‚¸±5å­ΪêuÕµ¶³+<Œ°yõre{`‘¡#§4Δ„ü˜2;v¦9Šÿ¤'kºXs„ÿs¦‹óϹNq±8p¹fRª¦Àæoþü­³ûM_ßœK I=t.ßhÉ74[Ý m–¤øðt<äwWý!Ìê+•h©xí(jká[¥Ï)¾·yÆŠÜzøfÚʋ÷2 +ùendstream +endobj +1911 0 obj +293 +endobj +1912 0 obj<>>>>>endobj +1913 0 obj<>stream +xڅ’;oà …wÿŠ;&ƒ] Ø„ÑmK+¥6Ù² ”8©ü*`µ?¿P«¢VFîýÎÎå=€܇á>óëÐD"º[sÀ ÄÑu2ƒ Äëìdm¿QöIµ•=ígûù\¼’2NQB=¹3²R¾ëj”†Z®«¡Q­5A•Æ^…‰×Ąý¦<„9N˜³uå¥2}îí¹k}g%"” wìéWl€.RÒ9Ð +Ê0¡~Û Íþ'=Z“Éš%è?g29Oð%Ø1.ÊÓl¡ì [3v ñêÎ?:«OÙôõuÀ¥R×¦ ù.¦|ýXyØhYäk1<î¶%”ÝÑ~Hw°­î*-›Fiϲdí-b¯ŒùΟQ_¢…qÜ| n(/Ñ—2‘†endstream +endobj +1914 0 obj +294 +endobj +1915 0 obj<>>>>>endobj +1916 0 obj<>stream +xڅ‘?oà ÅwŠ“ÁÔPlÌè6I»TJm²eA qSù_«ýøáXmµBb¸û½wðî#¸ƒ¸ÏàÐF"ºÛpÀ ÄÉu2ÆPâ¸x³vxVò¸_ì—Kñ  8MõÐÎÈZù®«Qj…®ÇVuÖU +{&^ö›òæ1gëÊ+eú<ØsßùÎZD J܋ç«|š;:¥Ü¥s& T7`BýØ Íÿ“ž¬ÉlÍPòŸ3™gø’éåiÈ´Tvԝ™»„xõçõ—l‡æ:àJ)(Ӈ|ó9ßÌm”‡A«²Øˆáq·­ êOöSº‡mu_kÙ¶Jx‘Ý(o{eÌHrkë”Q”‡Õ°tÚÈkô dn×endstream +endobj +1917 0 obj +290 +endobj +1918 0 obj<>>>>>endobj +1919 0 obj<>stream +xڅ’;oà …wÿŠ;&ƒ©¡Ø„Ñm’ªC¥Ôv¶,(%®+¿ +X­úë Ŷš¨îýμ";0\'n›à¦®¶0ƒâd; c(âiñlLßV¦uõ!‹ÃrY¼x”z4Œ#Dº×¢”®kk”úZªÊ¡‘­Ñ^ÆN…‰Ó„„SÂ#fmmy-õQU½©ºÖu6E¡Èž{^²; +Kǔ[#¯´Î”„ü˜P·íD3Äÿ¤Gk2[3ýçLfçž’ã¢<öÉfÒ ªÕc`SˆwþÖÙ¼‹¦¯/Î¥„´ÖÏw5çëޕûÖYº- „Ûý.‡¼;™7a¶S]©DÓH¥áA´ƒ¨Eè”!#_ù³Ä•(ÁÖ'úý3Øwy >Šî“endstream +endobj +1920 0 obj +297 +endobj +1921 0 obj<>>>>>endobj +1922 0 obj<>stream +xڅ‘KSà …÷ùwÙ.‚€$$Ëh[WŽ5¡»n˜Jc¼2úóI3Úñ1̰¸÷;繯ìNá:…C݈èj“á Ž®“rŽRO‹gk‡‡ÁžúÎìûåR¼Ž.N0bžÛY+ßu5ÆB­ÐõتΚ J€¯"ÔkbÊ¿S"9AÜÙºòJ™ƒ>}Nöµˆ0ÂîÑóUÞ˝°Ü¥s¦ T?À”ù±gš£üOz²¦³5Gø?g:;Ïð9Ö).–'!ÖRÙQwf +ìâş¿tÖﲚˀ+¥ hLòÍæ|S·Ô< Z•ÅF@ ·»mU´oÒ=l«ûZ˶UÚÀ½ìFÙx‹Ø+cNñ/‹gœ¡,l‡ói)Ñg¦Íendstream +endobj +1923 0 obj +290 +endobj +1924 0 obj<>>>>>endobj +1925 0 obj<>stream +xڅ’½nƒ0…wžâŽÉ€‹Áx¤MÒ©²eA©CSñWÛ¨}üÚ5 E­°îýα}®ß= ù0„±]çÖ»/½»Ì ¼˜NÌŠ¡|Ù¼j=d½Ò§Íi»-ßDäG¢:ªª¶kj”ºZ*뱝VNÆV…‰Õø„ý¦,„9FÌØšòN¨³¼úÚw¶³/½æÄË/š:¢Ü9¥q& 7`Bí¶3Íÿ“ž¬ÉbÍPðŸ3YœxÎtŠ‹òÈeš =ÊNMÍ!®îü£³ÿ¬Ú¡Y\i£z—o²äk'ÊÝF»<=”àÃÃ1+ è/ú£2Ëd_˪m…TðTucÕX ß*}F¾óg‰-ѐ£Ð dý ÌDž½/¸4Ž>endstream +endobj +1926 0 obj +291 +endobj +1927 0 obj<>>>>>endobj +1928 0 obj<>stream +xڅ‘?oƒ0Åw>ōɀ‹]ƒñH›¤S% +ΖÅJ ¥â_Qûñk˵QÔʒ‡»ß{g¿û0Dö``î8wÁƒî0QÙNÂJ@¼nތsÝô¦:mNÛ­x÷õXGˆ:ì8ÉZ¹®­Qêk™®çNõfòª0v*Lœ&$ì7å Ì1bÖ֖wj:ëf4ÍлÎ^Šì›×«xšZ:¦Üy¥u& ”7`BÝØ Íÿ“^¬ÉjÍPôŸ3YWø’êå±OµPfÖý´v ñêÏ?:û/ٍíuÀ¥RµÓàóM×|»SîíŠì „Çc^B9TæSڇåz¨µì:¥'x–ý,[g:eÈHt{ï”Q”úå0¾ìä%øÅSÝendstream +endobj +1929 0 obj +291 +endobj +1930 0 obj<>>>>>endobj +1931 0 obj<>stream +xڅ’OO„0Åï|Š9î¨m-Žèîz2AèÞöÒ¬]\Ã?K‰~|[ D‰Ñ@8Ìüޛö ol·±{ÏMp'‚›C +„ƒ¸ØNÌ9ŠA>>>>>endobj +1934 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6ft›¤S¥Ô&[”7•ÿlµ¿ «¢TH w¿÷Þ}F°;8…ÇMô$£‡ÂAž\'å¥ ‹÷aè ­ŽûÅ~¹”bŠŒ˜‡vVUÚw]±PËM56ºlP%@ˆWê51å)Aw¶®¼Òö`ÎýpîZßYË#ì^<_Å °ÌÑ Î((3£¡¼SæÇ^hŽÄ]z²¦³5Gø?g:;Ïð%Ó).&’i¡‡Ñ´v +ìâ՟uÖߪéëë€K­!¯mòÍæ|S·Q­Š|#!†çݶ„²; _Ê=lkºÊ¨¦ÑÆÂ«jGU{‹Ø+cNñ­­3ÎPV“‘i#oÑz•èendstream +endobj +1935 0 obj +289 +endobj +1936 0 obj<>>>>>endobj +1937 0 obj<>stream +xڅ’?oƒ0Åw>ōɵ]ƒa¤MÒ©R +ΖQ‡¦â_Qûñ뫵Q” +‹áî÷žíwþð(ûQ¸p•÷ ½»]T€<ÙN$D|]½ÓgªìÚV•æ¸:®×òݑܑ~HŽäa(*…][ãÜÕR]jÍàT!PŠ*ÊPã3ñ—Bˆ&4Ö֖7j(õ¹7ç®ÅÎVz$ öØË/{[:ä‰5rJëÌ@+ȯÀŒã¶3-‚ä&=Y³ÅZä?g¶8/ðìOBl¦Ì¨Ûa +lñâο:Û¯¢éëˀs¥ ­‡Îå/ùâX·Ñ&Kw|x<ìsÈ»“ù,ìÁöº«tÑ4Jð\´cQ£…J_°Ÿüc†%Nây W߂ˋ÷ ùo’/endstream +endobj +1938 0 obj +294 +endobj +1939 0 obj<>>>>>endobj +1940 0 obj<>stream +xڅ‘?oà ÅwŠ“Á6ft›¤S¥Ô&[”7•ÿcµ¿ «šVH w¿÷Þ½G°;8…U +Ç&º—ÑÝVá O®“rŽR/‹WkûR÷Ê(«‹Ãr)ßÈ'1îUißu5ÆB-7ÕØèÖA•!^E¨×Ĕÿ¤>>>>>endobj +1943 0 obj<>stream +xڅ’Írƒ …÷>Å]& ©PYÚ&vՙTÉ.'!֎œöñ Å8m&ӎŒ‹{¿s€sy0DöÃpŸ¸uì‚Üå0q¶„1”€8­^KiòF¶§Ãê°^‹7R†q„¨÷ºª¥ëÚ¥¾–©zêdo´Wŀ±Saâ4!a¿)a޳¶¶¼‘ú¨šÑ4Cï:[D(²§^~ÅÐÔÒ1åÖÈ+­3%¡¼궽Рñ?éٚ,Ö Eÿ9“Åy/¹ÎqQû\ i&Õë9°KˆWwþÑÙ~VÝØ^\J Y«Ÿoºäë¦ÊýF›"Ë„ð¸ß•PgóQكíÔP«ªë¤Òð\õSÕ:‹Ð)CF¾óO©+Q‚ý8n=;“—à ¶¥endstream +endobj +1944 0 obj +293 +endobj +1945 0 obj<>>>>>endobj +1946 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6ft›¤S¥Ô&[ä7•ÿlµ¿ «¢VH w¿÷Þ}D°;8…ûª6zÑÝNá O®“rŽR¯«·q¤Q•>®Žëµ| Tœ`Ä>>>>>endobj +1949 0 obj<>stream +xڅ’;oà …wÿŠ;&ƒ)PlìÑm’N•R?¶,(!n*¿ +XíÏ/Ûj£¨ˆáÞïàÀ{@ÛAà>vóØep·Kp(϶sŽb(O«Wc†j8 #«Ãz]¾yŒy,Œ0b«´¨¥ëÚc¾–©zleg´WE@ˆSê4!å¿)‘” nmmy#õQ]sé;×ٖF؞yYò'`‰¥#–Z#¯´Î”„âL™Ûv¦9Jÿ¤'kºXs„ÿs¦‹óÏ©Nq±4ò©æÒŒªÓS`sˆWwþÑÙ~Švh®.¤„¬Ñ½Ï7Yòuošú6y¶+!„Çj_@џ͇°Û«¾V¢m¥Òð,ºQ4Î"tʐÓïü“Ø•ìuðí`ßä%ø}¸endstream +endobj +1950 0 obj +292 +endobj +1951 0 obj<>>>>>endobj +1952 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6öè6I§J©M”%‹•וÿ°Ú_¶ÕFQ+$†»ß{ï>ØœÂ} ç6xÁÝ.ÂA\l'æÅ ^WoÆ GUyZÖkñî)æ©0ˆ9ê ËJº®­1æk™ªÆVvF{U„8¡NRþ›rI âÖ֖7RŸU=˜ºï\g+Œ°}òråOÀKG,µF^i)( Å ˜27v¦9Jÿ¤'kºXs„ÿs¦‹óÏ¡Nq±4ò¡æÒŒªÓS`sˆWþÑÙ~•íÐ\\H Y£{Ÿo²äە¦~Ð&ÏvBx<ì (ú‹ù,íÃöª¯TÙ¶Rix.»±lœEè”!§øæÚg(ñ»Iø´’—àJ endstream +endobj +1953 0 obj +291 +endobj +1954 0 obj<>>>>>endobj +1955 0 obj<>stream +xڅ’Áoƒ ÆïþïØdÂPäh×v§%Ò[/¤Rã¢âP³ýùƒaÍÖ4[$Þû}ð=Þ ‘ý0<&nÛ`#‚‡=Ì@\l'a % ÊUÝ÷YYn´n”ìN«Óz-ÞeÛ7·JAÖ Úç›.ùº±r¿Ñ6ÏöBx: +(ôeüö`£+#ÛV™^d7ÉÆY„N2òšºb„ý@î¾;–×à J„‘Žendstream +endobj +1956 0 obj +295 +endobj +1957 0 obj<>>>>>endobj +1958 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6ftš¤S¥Ôv¶,(&–+ÿ+Øj?~A8V5­î~ï¼{`{p +1œÛ`S{„Cq±˜sCQ®êaHËrÓ÷’9­NëuñæQæÑ0ˆ9ôhd¥\×ÖóµTWS«ºÑxU„8¡NRþ“rqkkË[eκƺï\gWaûîåʞ%–Ž˜°F^i)hù/0enì•æHüIÏÖt±æÿçLç¾&;ÇÅDä“ÍÔ8éÎ́]C¼ùó·ÎîS¶Csp®¤é}¾É’ol÷*ü m–î áéxÈ!ï/ㇴ;è¾Ò²m•6ð"»I6Î"tʐS|÷Œ3”ø%bÞËkð’‚endstream +endobj +1959 0 obj +294 +endobj +1960 0 obj<>>>>>endobj +1961 0 obj<>stream +xڅ’½nƒ0FwžâŽÉ€k»Ç#-I§Jip¶,Vp5 öñk׀Ú(Jb¸÷ÜÏö1l±{Ïuð$ƒ‡ÂA^l'æÅ óUÙuIž§jЧÕi½–ïc #Œ˜Ã޽*´ëÚc¾–˜b¬u3ô~*BÜ¡n&¤ü/å "â6֖SݟMÙ eÛ¸ÎVa»çåsx¶±tĄ ò“6™‚ѐ݀)sËÎ4Gâ.=EÓ%š#ü_2]’x¶:éb"òVzMÓOÂf‰WgþÕÙ~©º«®gZCRõ­÷»Yüº;~¡ôì$„ð|Ügµ—áSٍíM[U×ÚôðªšQU."t“!§?þv%F©u„oÿöNނoÅñendstream +endobj +1962 0 obj +291 +endobj +1963 0 obj<>>>>>endobj +1964 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6ft›¤êP)- ЉåÊÿ +¶Ú_¶ÕFM+$†»ß{ïÞØœÂ} ç&xȃ»Â!¿ØNÌ9Š!/VUß§EñܪTú´:­×ù›'™'Ã#æÈ£‘¥r][cÌ×R]ŽjãUâT„:MHùOÊADÄ­­-o”9몪®um`„í³—ëð,±tĄ5òJëLA+È~)scgš#ñ'=YÓŚ#üŸ3]œxvŠ‹‰È{Pè[36‡xõçoí§lúú:àL)HkÓù|“%ߨ®UøA›CºË!„Çã>ƒ¬» Ò>l¯»R˦QÚÀ‹lGY;‹Ð)CNñÍÕ3ÎPâ÷#È´–×à ”4‘±endstream +endobj +1965 0 obj +294 +endobj +1966 0 obj<>>>>>endobj +1967 0 obj<>stream +xڅ’½nà …w?Å“Á(6at›¤êP)µ- ЉåÊ[íãŠmµQÔÊÈýß9À¹¼°ýÜÇn›à!îö‡üb;1ç(†¼XU}ŸÅs;¨RisZÖëụ̈ͣa„sèÑÈR¹®­1æk‰.ÇFµƒñªq*B&¤ü7å "âÖ֖·ÊœuÕU׺Î.0ÂöÜË/}¶±tĄ5òJëLA+ÈnÀ”¹mgš#ñ'=YÓŚ#üŸ3]œxNvŠ‹‰È'›ªaÔ­™›C¼ºóÎîS6}}p¦$µé|¾›%_7Wá7Ú¦É>‡‡ ²î2|H{°ƒîJ-›ÆN^d;ÊÚY„Nrú¿ ®Äp4äöc°sy ¾þ ’‘endstream +endobj +1968 0 obj +296 +endobj +1969 0 obj<>>>>>endobj +1970 0 obj<>stream +xڅ‘?oà ÅwŠ“Á6ft›¤S¥Ô&[˕ÿÛj?~A8V5­î~ï¼{`{p +›ÎMð(ƒ‡½ÂA^l'æÅ ‹UÕ÷iQdª-õiuZ¯å›ç˜çÂ#æ¸ã Jíº¶Æ˜¯¥¦œݎƒWE@ˆSê4!å?)A·¶¶¼ÕÃÙTýXu­ëìd€¶^®ìXbéˆ kä•Ö™‚ѐÿSæÆ^iŽÄŸôlMkŽðÎtq^àk¬s\LD>ÖL“i‡9°kˆ7þÖÙ}ª¦¯oε†´:Ÿo²äÛ¥ +?h›¥{ !<9äÝeüPöaӕF56¼¨vRµ³2äßY<ã %~;b3/å5ørFñendstream +endobj +1971 0 obj +292 +endobj +1972 0 obj<>>>>>endobj +1973 0 obj<>stream +xڅ’½nà …w?Å“Á(6at›¤S¥Ôv¶,(&–+ÿlµ_(¶ÕFQ*#÷~ççòÀö#ð»un‚§>>>>>endobj +1976 0 obj<>stream +xڅ‘?oƒ0Åw>ōɀk»ã‘6I§J)-‹DſڠöãזµQ•Ê’‡»ß{g¿û`{p +1\Úੇâj;1ç(†¢ÜÔЖe¦LßLcÝwçÍy»-Þ=Ì<F1ŸŒ¬”ëÚc¾–êjjU7¯Š€§"ÔiBÊS"‚ nmmy§ÌE׃ì:û"Àۗ¯Wö,±tĄ5òJëLA+Èÿ€)scš#q—ž­éjÍþϙ®Î+¼d;ÇÅDä³ÍÔ8éÎ́-!ÞüùGgÿ%Û¡¹ 8W +ÒÆô>ßdÍ7¶›~Ð.K„ð|:æ÷×ñSڇu_iÙ¶Jx•Ý$g:eÈ)¾·}ÆJüŠD4oæ-øƒ<”endstream +endobj +1977 0 obj +294 +endobj +1978 0 obj<>>>>>endobj +1979 0 obj<>stream +xڅ’Ënƒ0E÷|Å,“;ã%m’®*¥àì²AÁAT¼jƒÚϯ§&¨úˆÅ̹wì;¼zBûØÄøž[ï^zw{„ƒ¼ØNÌyƒ,Wõ0¤e™)Ó7ÓX÷9­Nëµ|q4s´…CúhŠJa×ÖsµTWS«ºÑ8U„ ŠPÔø”§"‚ÜÚÚòV™³®œŒô ´G_>Ù#°ÄÒÖÈ)­3­ ÿ¦ Ç^iˆ?éٚ.Ö<ÿs¦‹ó_Ýãb"ráfjœtgæÀ®!ÞÜùKg÷^´Csp®¤é]¾É’/®V¸AÛ,ÝKðááxÈ!ï/ã[avÐ}¥‹¶UÚÀSÑMEƒ>*}N?ó1–6IâÖñëß`óì}ŧ•endstream +endobj +1980 0 obj +296 +endobj +1981 0 obj<>>>>>endobj +1982 0 obj<>stream +xڅ‘?oƒ0Åw>ōɀk»ã‘6I§J)-‹DſڠöãזµQ•Ê’‡»ß{g¿û`{p +1\Úੇâj;1ç(†¢ÜÔЖe®©åØëóæ¼Ýïžež #Œ˜cOFVÊum1_Ku5µªWE@ˆSê4!å¿)A·¶¶¼Sæ¢ëa¬ûÎuöE€¶_¯ìXbéˆ kä•Ö™‚VÿSæÆ.4Gâ.=[Ó՚#üŸ3]Wx‰vŽ‹‰ÈG›©qҝ™[B¼ùóÎþK¶Csp®¤é}¾Éšol+ü ]– +áùtÌ!ï¯ã§´;ê¾Ò²m•6ð*»I6Î"tʐS|gùŒ3”ø >/æ-øÁԓ}endstream +endobj +1983 0 obj +294 +endobj +1984 0 obj<>>>>>endobj +1985 0 obj<>stream +xڅ’½nà …w?Å“ÁÔPlÌè6I§J©M¶,(&–+ÿlµ_(±ÕFQ*#÷~ççò`ˆì‡á1qëÔO"xØqÀ ÄÙvÆP¢\ÕЕe1꺫Ž«ãz-Þ=H=Æ¢<Y)×µ5J}-ÓÕÔªn4^ÆN…‰Ó„„ý¥„9FÌÚÚòF™“®‡±î;×ي B‘=õòË_€¦–Ž)·F^i hÅ ˜P·íL3ÄïÒk²X3ýçLçžs½ÄEyìsÍÕ8éÎ\›C¼ºó¯ÎöK¶Csp¡dé}¾é’¯›*÷mòl' „çþ€¢?ŸÒl¯ûJ˶UÚÀ«ì&Ù8‹Ð)CF~òç©+QœÌ¹õìTނoёendstream +endobj +1986 0 obj +293 +endobj +1987 0 obj<>>>>>endobj +1988 0 obj<>stream +xڅ‘Ënà E÷þŠY& SC±1K·Iºª”Úd— Љåʯ‚­öó ¶ڨ!±˜9÷Üy 0Dö``Áƒî0qµ„1”€(7õ0deYŒºî*sޜ·[ñêIêÉ0ŽuäÉÈJ¹®­Qêk™®¦Vu£ñª0v*Lœ&$ì;å Ì1bÖ֖wÊ\t=Œuß¹Î^Šì³×+šZ:¦Üy¥u& ?À„º± Íÿ“ž­ÉjÍPôŸ3YWx vŽ‹òØ›«qҝ™[B¼ùó—ÎþC¶Csp¡dé}¾éšob×Êý ]ž„ðx:Pô×ñ]ڇu_iÙ¶Jx–Ý$g:eÈHôëê)£(õûá|^ËKð Ӝ‘ñendstream +endobj +1989 0 obj +293 +endobj +1990 0 obj<>>>>>endobj +1991 0 obj<>stream +xڅ’½nà …w?Å“Á(6atë¤S¥Ô&[”˕ÿ +¶ÚÇ/Çj£¨•‘‡{¿s€sy`÷¸Oý:µÑƒŒîvyv”s”‚|]ÕЫQË^Ö­>®Žëµ| $ dœ`Ä>>>>>endobj +1994 0 obj<>stream +xڅ‘?oƒ0Åw>ōɵ]ƒñHKÒ©R +ΖÅJDſڠöãזµQ”Ê’‡»ß{g¿û 0 {00 œÛàI{˜¸ØNÂX”€xßÔЫFê´9m·âÃSÔSaŒ"ꨣ‘•r][£Ô×2]M­êFãU1`ìT˜8MHØ_ÊA˜ãˆY[[Ε9ëzë¾sP„ì“׫xšZ:¦Üy¥u& ”7`BÝØ…f¿KÏÖdµfúϙ¬Î+¼„:ÇEyìC-Ô8éÎ́-!^ýùWg÷-Û¡¹¸T +²Æô>ßtÍ7±+å~P^d{!<%”ýeü’öaÝWZ¶­Ò^e7ÉÆY„N2‚n®&鲌𼓷ào3ŽÓendstream +endobj +1995 0 obj +289 +endobj +1996 0 obj<>>>>>endobj +1997 0 obj<>stream +xڅ’½nà …w?Å“Á(6ñè6q§J©ílYhB,Wþ+`µ_(¶ÕFU*ýß9À÷€¶ƒÀ}ìæ© Êà.K€p(/¶sŽb(Ï«z²º;§Æ¨úu4ò¸:®×囇™‡Ã#æàƒ•t][cÌ×RU­ìŒöªq*B&¤ü7å ’Ä­­-o¥>©z0u߹ή 0Âöä˒?ÛX:b‰5òJëLAI(þ€)sÛÎ4GÉMz²¦‹5Gø?gº8/ðœíK"Ÿm.ͨ:=6‡xuçÝ§h‡æ:àBJHÝû|7K¾îe¿Ñ6O³Bx<ì (ú‹ùö`{ÕWJ´­TžE7ŠÆY„Nrú?ÁÔÕ¦Ößúöi^‚/Èy”‹endstream +endobj +1998 0 obj +296 +endobj +1999 0 obj<>>>>>endobj +2000 0 obj<>stream +xڅ‘?oà ÅwŠ“Á6ft›¤K+¥6Ù² ”¸®ü¯ØVûñ ¶Ú(j…Äp÷{ïàÝG@ÛC€SØÄp®ƒ{Üíòb;1ç(ùº*»îI7ÅðvZÖkùî)æ©0ˆ9êØ«B»®­1æk©)ÆZ7CïUâT„:MHùoÊADÄ­­-ou6e7”mã:;`„í“—+{–X:bÂy¥u¦`4ä7`ÊÜØ™æHüIOÖt±æÿçLçžCâb"ò¡fzMÓOÍ!^ýùGg÷¥ê®º8×Òªo}¾É’olW*ü m–î%„ðp<䐷—áSهL[U×Úôð¬šQUÎ"tʐS|sí,NæÝ¼™vò|äŽóendstream +endobj +2001 0 obj +291 +endobj +2002 0 obj<>>>>>endobj +2003 0 obj<>stream +xڅ’½nà …w?Å“ÁÔlÂè6I§V©M¶,(%–+ÿl¥_(¶ÕDQ+#÷~ççò`ˆì‡a•¸uªƒG<ì8`âl; c(ñ¾(»îU]Ž‹ãr)>>>>>>endobj +2006 0 obj<>stream +xڅ‘?oƒ0Åw>ōɀk»ã‘6I§Jœ-‹•:ˆŠ5 öãזµQ”Ê’‡»ß{g¿û `{p +1œ›àI„ƒ¼ØNÌ9ŠA¾oª¾Ï:3ž6§íV~x†y&Œ0bŽ9ªÔ®kkŒùZjÊ©Ñí8xU„8¡NRþ—rqkkË;=œMՏU׺Î^aûàõÊ_€%–Ž˜°F^i) Å ˜27v¡9wéٚ®Öáÿœéê¼ÂK¤s\LD>Ò\“i‡9°%Ä«?ÿêì¿UÓ××ZCZÏ7YóíB…´ËӃ„žYEw¿”}XfºÒ¨¦Ñf€WÕNªv¡S†œâKgq²l†àhÞÈ[ðÉB{endstream +endobj +2007 0 obj +288 +endobj +2008 0 obj<>>>>>endobj +2009 0 obj<>stream +xڅ’½nà …w?Å“Á6ft›¤S¥Ô&[”˕ÿŠmµ_(¶ÕFQ+#÷~ççòÀö#°‰Ý:×Á£ öyµ˜sƒ¼¬Ê®Ë´ºœV§õZ¾y†y&Œ0bŽ9öªÐ®kkŒùZjбÖÍÐ{U„8¡NRþ›rqkkË[ݟMÙ eÛ¸ÎNa{àå—=K,1a¼Ò:S0ò;0enۙæHüIOÖt±æÿçLçž#âb"ò‘fzMÓOÍ!ÞÜùGg÷©ê®º 8×Òªo}¾É’¯¨ðm³t/!„§ã!‡¼½Êì`Ú¨ºÖ¦‡Ռªr¡S†œ~çOpìjl“̹yv"¯ÁSM'endstream +endobj +2010 0 obj +290 +endobj +2011 0 obj<>>>>>endobj +2012 0 obj<>stream +xڅ‘1oƒ0…w~ōɀk»ÃHKÒ©R +ΖÅJD…PûókˀڨMeÉÃÝ÷ÞÙïÞØœÂ} g<ˆànŸá .¶sŽb¯›ºïE­•èr9ªÓæ´ÝŠ7O2O†F̑ÇAVÊum1_ËL5iՎƒWE@ˆSê4!å?)‘” nmm9WÃÙÔýXw­ëìD€¶Ï^¯â Xb鈥ÖÈ+­3£ ü¦Ì]hŽÒ›ôlMWkŽðÎtu^á%Ø9.–F>ØB“i‡9°%Ä«?ëì>¥î›ë€K¥ k†Î盬ùÆv­©”Ù^@ÇC ew?¤}ØÁt•‘Z+3À³l'Ù8‹Ð)CNñŸ«gq²ì‡`>ïå%ø֑Óendstream +endobj +2013 0 obj +292 +endobj +2014 0 obj<>>>>>endobj +2015 0 obj<>stream +xڅ’½nƒ0…wžâŽÉ€kƒñH›¤S¥ˆ²dA©ƒ¨ø« j¿v ¨EU+,†{¿slŸë76 ²ëÚx÷¹ww@8ä7Ӊ8Gä/›ªïϪäesÙnóW1ù!FÌB']”ÒvM1WKT96²´S…@ˆUj5>å?) A7¶¦¼“úªª~¨ºÖvö¹‡6'^~é#°ØÐ!ÆÈ)3%!û¦Ìn;Ó‰?éɚ.Öáÿœéâ¼Às¦S\L„.ÓT£jõØâêÎß:û¢éëuÀ™”ÔºsùÆK¾v¢Âm´K“C><œŽdÝmx/ÌÁŽª+UÑ4Rix*Ú±¨­…o•>§_ùÛ  +ÜDÖïÀŒäÙûûŽDendstream +endobj +2016 0 obj +293 +endobj +2017 0 obj<>>>>>endobj +2018 0 obj<>stream +xڅ‘Ënà E÷þŠY& S Ø˜¥›GW•Ò˜ì²A ±RùU°Õ~~AØVE©X̜{î|F°;8…çNuô"£§­ÂA^\'å¥ ϋ®;¯ªÖêãâ¸\ʏ±Å FÌC«Jí»®ÆX¨å¦jÝô6¨ Ä«õš˜ò¿”‡ˆ ˆ;[W^k{2×®¿¶ïld„v/ž¯ý+°ÌÑ Î((3£¡¸SæÇN4Gâ!=ZÓٚ#üŸ3gxÊtŒ‹‰$dº×ý`;6…xóç_Í·ª»ê6àBkÈ+ۆ|³9ßÔmT„Aë}¾•Ãê°+ h/ý—rۙ¶4ª®µ±ð¦šAUÞ"öʘS|oë,ͦÕ,ƕ¼G?WŽendstream +endobj +2019 0 obj +288 +endobj +2020 0 obj<>>>>>endobj +2021 0 obj<>stream +xڅ’»nƒ0†wžâŒÉ€k»Ç#Í¥S¥œ- "Qq« j¿vMPõ"Ã9ßùmæ5 €íCà>voÑ2¸; di;1ç(yY ÃeÛweS£9¯Îëµ|ñ ó`aÄx2y¥\×ÖóµDWS«ºÑø©qS„º™òˆ ˆÛX[Þ)Sèzë¾s½ 0Âv×Ë'}¶±tĄ ò“6™‚VýS施Ò‰?é9š.Ñáÿ’é’¼ÀW¯³.&"ï5Uã¤;3 »J¼9ó—Îþ=o‡æVp¦$é½ßÍâ×ݪð íÒä !„íé˜A֗ã[n7vÔ}¥ó¶UÚÀSÞMyã"B7rúéŸìjŒ+ ÿö/Øky>äü‘dendstream +endobj +2022 0 obj +294 +endobj +2023 0 obj<>>>>>endobj +2024 0 obj<>stream +xڅ‘1oƒ0…w~ōɵ]ƒñHèT)²e±‚ƒ¨0Pj~mPE­,y¸ûÞ;û݇‡™ƒxŒà¢¼§Ò{È8`åÕt"ƂÊj7TUªš)«Î»ó~_¾;Š:ÊQ@-uE-m×Ô(uµD׳’Ý4:U[&Vãö›²æ8`ÆÖ”r¼èf˜š¾³´ôP€Ì“·+:¤Ü9¥q& %w`BíØ•fÿ“^¬ÉfÍôŸ3ٜ7x u‰‹òЅšËiÖݸ¶†xóçôK¨¡½ ¸’vì]¾ñ–odVÊÝ Cžd%øð|:Pô×éS˜‡u_k¡”Ô#¼Šn­µð­ÒgÝ];âu7ãe'oÞ7QŽ~endstream +endobj +2025 0 obj +289 +endobj +2026 0 obj<>>>>>endobj +2027 0 obj<>stream +xڅ’½nƒ0…wžâŽÉ€‹ÁñHÒ©R +dËb%¢â¯6¨}üÚ5 E­°îýα}®ß= ù0„±]—Æ{,¼‡Ì ¸™NÌŠ¡¸núþš6Õpޜ·ÛâÍ1Ô1~ j™“¥´]S£ÔÕUŽlíT`lU˜XOØoÊB˜cČ­)量¨ªª®µ´ð˜/¿ìèÎÐåÆÈ)3%!¿j·i†øŸôdMk†‚ÿœÉâ¼Às¤S\”G.ÒL£jõØâêÎ?:é§húzp.%$µî\¾»%_;Pî6ÚgÉ¡žNÇòî6|s°£êJ%šF* /¢Em-|«ôùÎcbk4ä(tY=3‘Wï pS=endstream +endobj +2028 0 obj +291 +endobj +2029 0 obj<>>>>>endobj +2030 0 obj<>stream +xڅ‘?oƒ0Åw>ōɵƒa¤IèT)gËbC©øWj?~mP5­,y¸û½wö»wÒ#° oœGî<$`üª;c^¼Øô}‘Tm±íª\^6—í–¿Y’ZÒõ‘G yD)MW×(µµX•S#Ûq°*06*LŒÆ%ì'e ai[]>È!WU?V]k:Gî ég¯Wú4Ô´O#md•Ú™€’ýjÆ.4ó¢?éٚ¬ÖÌCÿ9“Õy…—`ç¸häÛ`S9NªæÀ–oþü­süM_ßœI q=t6ßpÍ7Ðkì C'\؟OdÝuüúa'ՕJ4T<‹vµ±pÒeÝ]= Âe?ïæ½¼8_‚‘¾endstream +endobj +2031 0 obj +293 +endobj +2032 0 obj<>>>>>endobj +2033 0 obj<>stream +xڅ’½nƒ0…wžâŽÉ€‹]ƒÃH“Ð)R +dËbCiù« j¿v ¨‰ªTX ÷~çØ>×O³òÆyʜ‡8Ì »èNÀ + +V}_ÄU[¸|Åöµ«rq^×ëìÍòÔò®ï!jø“â¥0]]£ÔÖ"YŽheU>`lT˜KØ5e bÄ´­.ï„ÊeÕUךÎ>s<äéÃ/¿äèFÓ> µ‘UjgR@úL¨Ùv¦ +ïғ5Y¬òþs&‹óÏñNqÑзñ&be«¦Àæoîü«³ÿâM_ßœ +Q­:›ïfÉ× 7´í’(ÎÀ…íé˜BÚ]†O®v”])yÓ©àÀÛ‘×ÆÂ5J—‘Ÿü1¦¦¦ì<î<=›ç~š–endstream +endobj +2034 0 obj +299 +endobj +2035 0 obj<>>>>>endobj +2036 0 obj<>stream +xڅ‘Ënƒ0E÷|Å,“Ôv ÆKڄ®ª¦@vÙXÁAT¼jƒÚϯ]j£>dɋ™sïØw^= È ŒÀmçÖ»+¼›”fP\L'b,ˆ (7ÃP¦uW> cÝw§Íi»-^Ié‡( –#è×ÕÓ(^öƒq8ïåÙûj’endstream +endobj +2037 0 obj +292 +endobj +2038 0 obj<>>>>>endobj +2039 0 obj<>stream +xڅ’½nà …w?Å“ÁÔPlÂè6IÕ!Rj“- Љ•Ö[íãŠmµQÔÊÈýß9À¹¼"ûa¸OÜ:ÕÁƒî¶0q¶„1”€(]W<›Ôoª8.ŽË¥xõõ\Gˆ:î`d©\×Ö(õµT—C­šÞxU ;&Nö›ræ1kkËkeNúÒõ—¶q"ÙCÏ¿ì èÊÒ1åÖÈ+­3­ ¿궝h†øŸôhMfk†¢ÿœÉì<ÃS¬c\”Ç>ÖLõƒnÌØâ՝t6Ÿ²îªë€s¥ ­Lëó]Íùº¡r¿Ñ:K·Bx<ìsÈÛsÿ!íÁöº-µ¬k¥ ìd3ÈÊY„N2ò?Ɖ«Qœ ì'rã)Ø©¼_©>>>>>endobj +2042 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6ftë¤S¤4v¶,(ÁVZÿ+Øj?~AØVU©î~ï¼û`{p +1œ›à©¶‡¢´˜sCqYõýe'õ{¦J9փ9­NëuñæYæÙ0ˆ9öhd¥\×ÖóµTWc£ÚÁxU„8¡NRþ›rqkk˙2g}í‡k׺Φ0ÂöáËux–X:bÂy¥u¦ äÀ”¹±3͑¸KOÖt±æÿçL瞣âb"òÑÔ0êÖLÍ!ÞüùGgó%›¾¾ 8W +ÒÚt>ßdÉ7¶‹~PvH·„ð|Üçwåð)íÃöº«´l¥ ìd;ÊÚY„NrŠï,ŸÅɼ!Bø´™×à^º“°endstream +endobj +2043 0 obj +294 +endobj +2044 0 obj<>>>>>endobj +2045 0 obj<>stream +xڅ’Os‚0Åï|Š=ê4I!GZµ'§âÍKF#cË¿˜öã71ÈTÇi†Ãîï½MÞòÀö!ð»w_O2xX äÑvbÎQ ò0kÛÃZ™×¶?5õn¶›Ïå»'™'Ã#æÈm§ +íº¶Æ˜¯¥¦*]÷WE@ˆSê4!åהƒˆ ˆ[[[^ènoNçÁ®³”FØ{úd/ÀKGLX#¯´ÎŒ†üL™{¡9Ò£5¬9Âÿ9ÓÉy‚/ÁŽq1ù`3ݦîÆÀ.!ÞÜùWgù­ª¶¼ 8×Ò²k|¾É”¯[«ðƒYº’Âóv“CÞû/e¶1MaTUiÓÁZՃ*Eè”!§çü I\a†"¿‘»?ƒÝË[ðNè’'endstream +endobj +2046 0 obj +295 +endobj +2047 0 obj<>>>>>endobj +2048 0 obj<>stream +xڅ‘?oà ÅwŠ“ÁÔPlÂè6q§ª©M¶,(&V*ÿ+Øj?~AØVE©î~ï¼û 0Dö``85Á“2˜8ÛNÂJ@”«¾/ßzÕfåqu\¯Å‡§¨§Â8BÔQ#+庶F©¯¥ºÕÆ«bÀØ©0qš°¿”ƒ0LjY[[Þ*sҗ~¸t­ëìD¡È>y¹ò Kǔ[#¯´Î´‚âL¨;Ó ñ»ôdMk†¢ÿœÉâ¼Às¨S\”Ç>Ô\ £nÍØâ՟uvß²éëë€ ¥ ­MçóÝ,ù&v¥ÜÚæi& „çþ€¢;_Ò>l¯»J˦QÚÀ«lGY;‹Ð)CF¢›k§ÉfÞ Æ|ÚÉ{ð1Ύ¤endstream +endobj +2049 0 obj +290 +endobj +2050 0 obj<>>>>>endobj +2051 0 obj<>stream +xڅ’Írƒ …÷>Å]& ©P”°´MìªÓTÉ.&!Žÿ +:íãŠ:m&ӎŒ‹{¿s€sy0DöÃpŸ¸uj‚Üe0q±„1”€8¯úþüÒ«6«ju\×kñæ9ê¹0ŽuÜÁÈR¹®­Qêk©.ÇFµƒñª0v*Lœ&$ì7å Ì1bÖ֖·ÊœtÕU׺ÎNŠì¡—_þtcé˜rkä•Ö™€VP܀ uÛÎ4CüOz²&‹5CÑÎdq^à9Ö).Êck®†Q·f +lñêÎ?:»OÙôõuÀ…RÖ¦óùn–|ÝP¹ßh›§™€ûŠî2|H{°½îJ-›Fiϲeí,B§ ùÎßNÉÕ(Næ‰Üx +v*¯Á pAendstream +endobj +2052 0 obj +293 +endobj +2053 0 obj<>>>>>endobj +2054 0 obj<>stream +xڅ‘?oà ÅwŠ“Á(6at›¤SÕÔ&[”+•ÿlµ¿ l«¢TH w¿÷Þ}F°;8…ÇŽuô$£‡­ÂAž]'å¥ O‹®;½uº9,Ë¥ü Lœ`Ä<³·ªÔ¾ëjŒ…ZfÊ¡ÖMoƒ*B¼ŠP¯‰)ÿKyˆ‚¸³uåµ¶GséúKÛøÎFFa÷àùÊ_€­0ጂÒ9S0Š0e~ìDs$îÒ£5­9Âÿ9ÓÙy†§HǸ˜HB¤¹îÓØ1°)Ä«?ÿêl¾UÝU×ZCVÙ6仚óMÝBE´Î³­„ž÷»ŠöÜ)÷°iK£êZ ¯ªTå-b¯Œ9Å7–ÎÒÕ´Bɸ‘÷蔍Iendstream +endobj +2055 0 obj +288 +endobj +2056 0 obj<>>>>>endobj +2057 0 obj<>stream +xڅ’½nà …w?Å“Á(6at›¤K+¹6Ù² „¸©üWl«}üB±­&ŠZy¸÷;8—€¶ûØ­C<Èàn+€p'ۉ9G1Èã¢m©*ô³®‹þm¿Ø/—òݓ̓a„s䮳œëÚc¾–˜b¨tÝw^!NE¨Ó„”_R"‚ nmmy­»ƒ9·ý¹©]g#Œ°=öü˞€­,1a¼Ò:S0ò0enۉæHüIÖt¶æÿçLgçž‚ãb"òÁfºLݍM!^ÝùWg󥪶¼8×’²k|¾«9_7Vá7ZgÉVB»4‡¼9õŸÊ,5MaTUiÓÁ‹ªU:‹Ð)CNò'”ºÃÔÏãæS°Sy ¾߁‘sendstream +endobj +2058 0 obj +295 +endobj +2059 0 obj<>>>>>endobj +2060 0 obj<>stream +xڅ‘Ënà E÷þŠY& S ؘ¥Û$]Urc²ËÆJˆåʯ‚­Výú‚°­6êCH,fνw^ØœÂ&†sÜËàn/€pWۉ9G1È˪ï/YQª¼úP§Õi½–/žcž #Œ˜ãŽÆR®kkŒùZªË±Qí`¼*BœŠP§ )ÿN9ˆ‚¸µµå­2g]õCÕµ®³“FØ>z¹ÀKGLX#¯´Î´‚ü˜27v¦9ғ5]¬9Âÿ9ÓÅyçX§¸˜ˆ|¬5Œº5S`sˆ7þÒÙ½M_ßœ+im:Ÿo²äÛ¥ +?h{H÷Bx8f9äÝux+ìÃ2ݕºh¥ <íXÔÎ"tʐSüËâYœÌÛ!t3må9øCxWendstream +endobj +2061 0 obj +292 +endobj +2062 0 obj<>>>>>endobj +2063 0 obj<>stream +xڅ’½nƒ0…wžâŽÉ€‹]ƒã‘6I§JeÉb‡RñWj¿v ¨¢VX ÷~çØ>×ï†À|î#»Îµ÷ ¼»=Ì@\L'b E òU×å‰,Ա̇×Óê´^‹7Rúa€¨½Ál×Ô(uµXc­š¡wª0¶*L¬Æ'ì7e!Ì1bÆÖ”·ª?ë²ʶ±ð˜S/¿ô èÆÐ!åÆÈ)3­ »j·i†øŸôdMk†‚ÿœÉâ¼Às®S\”‡.×T £nú)°9Ä«;ÿèì>eÝU×gJA\õ­Ëw³äk§ÊÝFÛ4Þ ðáñdµ—áCšƒ%º-´¬k¥{x–Í(+ká[¥ÏÈwþ˜P[£C¡›È­·`Æòâ}Ž‘endstream +endobj +2064 0 obj +296 +endobj +2065 0 obj<>>>/Annots 209 0 R>>endobj +2066 0 obj<>stream +xÚ͛AwÛ¸€ïþ<¶‡( €àÑkÇ»éK7V#юº™•¨¤ûï‹Á @²ú°÷œ |ƒ™0þãŠe¹þòªÈJ™­vW¿,¯ÞßÕY‘gËnj‰:“ϖë¿-›¯Û6ë³›¾Ún8ü}ù߫˫|‘k|cðí˯ÐÈd)*Ûeú/NmöðùýSöþNdŒÁƒqR‹êw¿o›U ?¤,¥îÒÿ¹˜ý{Q+zbzzE±Z-[0jZÞßqR‚^Y”ºGOøáÏÃÐg§‡ó…©ÔO´Ï?ÚýMûpœ-ê)5¥·¼Öv´Ë×3ÁÍ´Åò…1ÑÛ~uÜiÓ|Y_Þx­¯¢Ò:hØoy¾ŠE1}±èƪÔßµ¦ôÇŏæv™Pf~,¢¨q¸ÖS¥÷_ÀÂ^Ãx÷2÷ËD­-1€P7Çݾé†M÷ô2Ì¿Ëj¡ =€Q7Ÿ²i¼Ñzr<_T!‹úÏM@\ÜÊø6²6^WmØØxνˆ*G'»üÖF4î Zãôë±Û’Ò è´ÖK‹ïó°ßñznvÆýC™ÃÎK)_Hã†Q1¦á|”úà *'˕žx¢~‹jWߺ~Û?ý @ÁôÿÎ)Jò„ºxi¼°ž“¤†§.ÎÑÿ£ÿj VÏ?HM¸ÌµÛÜeÚèmÛ°ÞLïfÛíóžÏ85YíÝÁ½J³«MÛ,3{ün³Ú½™ªŽÄbÖ˛šn^¿&Óð¦›sÏI¶û—÷¿7ö?;…Q?án÷›¤?mMrnúq•ñ:7nN)½ôØp*ã5C÷¯vøÙïבŸ¸bž^@DS2®7AA)þû™”ŒK ˆ'ef²§€†½DI¥eSBŒ 0ÔMœh¸ò·¦Buéæ?÷Ëw£Iœ ¨›P×÷MLP3I N¾ª„áëHÛ<Ï%i\ÓòËSR»Ú€GÝÔsd}J¢~Cú´ùºoö&ç(‹­ÀËj¯ +P{Y¡[ek°eOÉz㔊œj;´«x&ë •-µSxV€Cl ýᦍ>?‘Áâëè×´º>ûh’;­dçvYÁØÙ‡#nº—YþhÍpK°´€#]‡~ÕwÆÊê¿09Hmւ›(%Kð®¦áE©B`”ú¥9lVçæCXÏÁ8|õìNœ+JaßÍÌÅ¥ö™^gs»’W`¦åí3V`bÿ±[mëØÆðÆÃ]ñI>Í +Pg“-桱„žÊZa Ïa`Ëé©ÔËxÛ_Û!፼ñ §Rûü€f÷FÞpðF°óB ìúG³Ùš‹áˆKr½ïs©—+D’!)I>D<‰ÇÐD½oXH´Dlºuæ ·¤Î`$PŸŸÏò¿ì +5e;JP¤†S$¶<ÛQrڕŒ?ïdd³òdƒÍ$ W -UŒRaËӒ–Qèo“;̍5)P“O³ÅÄcž€L¾û€$@ÀÏ߇Mß(ãºP@H)[( oøclyÊ5·›¦[µÛm\ß.h~tB(@ÌñŽHÍ Xªx>Qra♔°±LÃå%—Ë~[.ï#é„ Æm¬Ç'Q?±‚tÞáæ•N¤Ìª,Æ(YQË3«²D¯<1›i&›hV€€³Ë&Rzb5:ñ/°åé©0s¸é».y¸ñàìà96À‘‡>æåÜXØÆp£’PIMä EwÉN@(€ °÷vo.å¥âTj±rá¦\„)—¯ L–Æá®5 Y~iÿ8¶‡!®iæ€?¬§iæ€w›v»>®å,u]Ôô8®?³ –ÓuQÓÓøÇÃá˜ÐµOíEH³ŒÙ³7– ÂXˆ"BѲÎ/}ϛRwU§?E-O݊^Ö'žjFš9u4°À §š&!‡ +a(`aé}â!4PÕãÌÇ3°À‡¡ޏOÄÛç(©%3ù&µ¼%“Fć¶['OÊÑx=²½Ó„rÀ Þ¨ö?ž¹¼v¸Ûfh.°SjTp`î0°å©Yå5)%»Ñ£ïðYV€OV±t¸*?ýhV€*¾ÜÅ{"½.J*€?‰ —^œŠ >ÞG²koè.«¡J*à`·%ÜÕÍñ9"e–…­6€ü[žYTk01Ái&ÁhV€€³K°ë„ž–+0[žžÕ+ÜìÛ&ué☯«gˆØtñd]9–IƒC +jøþpð5˜~#DÉ ¦%©%Ësï†[ޒåTqq½^OIE,L°S˜°¼aØo¾4o^^øÈPSÕx•¨¨å”Ä”zEìY& +XV@¥MڍÅËyB"5Á Ý`0h5Nw4hP§æ /nX³ÔRUTbB<¶¼¥ª¸=åMÊ!FZUÃÍ +0¾\n4,\Ÿ„,à‹) æ†CZ-N§iƙ¾÷Ý¡¥zæ·?ì§Læ[ë±å-˜d6¦v—75ÝÓ±yŠÝh¬&ã +{Ÿ¯v™Ï :a‹Ê¯rQa‘‹z]‹òK\ÔY…‹škKBCÒ¯o‘ay‹|]u‹ô‹[äYm‹œ^ÚbIêÖäYa‹%ݶÍq»8s(j'©€†ÝD³æÍóT–Ç—HPå‡Ñ¢«H„|ÅYQ¢¢n9qy,§Êá×Äé©OLô?Þx([„gކÝö¡[õk*/³ß‰L­ ·…+ <Ö­p* +™¸2Åà0Ń¢ÓM´èsÕ8tgN"ä`7q&¬#@N¢N?vÛڝUãÚâ­Ïä‘E»f¬OÊ<‘² Ê”ûûÛÈEó8PgŒðªáC°³~&Fòٕp¦Ü óñ»•­g‡-(kû{º_®ï–Ù»Ì$jýãð³Ù·Ùý¾Ú7»Ôþý³éŽÍKV@+ï*|Üߐ6ÿ}õãξâendstream +endobj +2067 0 obj +2496 +endobj +2068 0 obj<>>>/Annots 253 0 R>>endobj +2069 0 obj<>stream +xÚ՛ßsÛ6ÇßýWð±}°Bü"ÁÇÔ©“Î8S­»{é +Ó>^%ÊGIé]ÿúÃb 8€2)•üðhà#b,¾X0ÿ¹bEi~³BTðg½½úauõæ¶)xY¬ž +¦š¢ªe±zünÕþºéŠÝSq³ÝpØ¿ú÷Տ««rQü`ðãþ}QóEYTB-t±-XY/j²6ÅàOZŒÏś[Y0_XsS·2uÍ7þ4¬7ÇÇ®øâ…lóM¼Y°ø›\Þö›Î>6kLŸÍ?,fýÅʌ 9_TÐ1Æ’,급 c›NÜíÚÇ~xN¸)h´fb;7Q¶)T>˜äŸ£Z.ß%P2ꣲƒ¡dÐI:;rj¶‘ËWÙ/ŒoÌ3£ +výürèwÃ>5«}{˜ÕzÁcUpÀvxLÀ‚æV•§Fìý¸;¾Ø5"Øb6_ç\­šÊ<4ºÚYÞÕª©m'͐YA{p57s0¢™ +×)?û¶0›¹‰;1‰* gà8 Æ|Ñ(ëj-ÌÏÉÕÖ +\­å×8Ú±Xe¦aIJŽFX2üø†~J×c U° eûœÚ<‚ÖêU°¬‡þŒ?0¤—TÕàNÈ Œ¢ŒU]â6ø±Ël¾=¸¹6‘ ¢Q¤f£†˜u6Ÿá#UÑ6X-²©÷››u뜓<Àà'…8WˆO»1 š˜yR}£ +îñvÃÓ¦_£z!æðyÖÕRà®ÃìB²Vàj)qËyèrÁ#hÓQÁÜ i®‚ŒvXë>ótL9©±ÚÆ؄ñ3õéÍ­"I •ì2_v‘o³ÇL‡ˆ…¥–qp³o·5kûBŖòϱ?$‡L…,]Ãè„,°Œ²;t£-+E.@˜Ÿ!ûb?ÍÉ O)l ¬a'GcDw®1g+UJ +—ŸºñSßýTÉæY»ª×vu˦ N'hùÕ-†‘ê¡[Ílù_îx2áêúç*°)öíûÇnl§U^cÿr'fd{²Î0hª5F«U·}ٍí˜òP@ÀXƪªå´’ Ú:µ‘¨œXo×ëÝq€ðe×_³˜7 .R1ÒÌl²¨_&¦HÅqIl·æx}×]z¡@‚.š +Žøv|>n]–Gê9ÖיHÔ6ø6V€5‚ $4†Ü›ÝKb}m§ ’¨œXﻁ‚õM=·àå™ Ä¥ ¬ö0ŠF0¸Â úãð©w yr¡ñ‰Ç¬ìŒ€TNÈ´c9Ã=ísÕÜû\ÖSvŸ1û¸˜ŒÀSŒcpÍjŸ ¹Ñ>°E¬ZxVâ¨4„Å/aN†*'ЇÕÇ»ÔÂ÷Íqàd sø´If™˜_‘%† ´ÐjRÐøù-´’2­ ÊJ݈…¥Õ9 +ÚAÔg*®ÎWЎÕÈS– +X˱Ìx%Ö­ X&¯c•[Ø»±ÿDr\¨‹ãL¤—­¨™—ßh¼&¿…=T;ò[¤÷=¡´ ëŒ ¿ï ÕP>/œ÷½ˆDåĺ4á”s‘Éî9h’†º›Ý&•— ƒb‚äm„¢r‚}lãoØChkϖ*Ì-Á­\® G…†ß넨•ïÛ}2°­1ÍÃc•íö8¬§3›œ;Qøu“ÉÞ{Á€]­`6qۑõñeûù¥~ùî—ïZWó‰ç³ºVÒõ©öVе’îN}çî»öñƒùۍ®‹ÝÿËûÈdº_¼áSB‘åûźXŒûµìÿÛmö¾_rŽí!Û³šnóì-ZAÏ4]åùžÝlvûnšÍ|÷zéÎÙÀÄ+¼B³* ˜xE×gç‰pDzZ9b>±r"ÜQ É¢c •èÃòzys—NãhSÑp®ñPŠY¯1\䘁ç/Š@$ãçW8—tY¤ÒÜÁ¬XŽh¶ÔQr*ÜaÔg,vœótøôP¥³§"Üíú·nxÄNÎ:h¯ £Ê,=Ž×O6  ñšæœ.¡¾!­2є¹[*ØÚÑ +¢)›n©ÎËcO8›Ÿp®‚tÒóBòØ9•åÿ*²• £ÕÙyì‰góØÏU`îýËÉcgœÄ4ÞuÙ#ÞGLë3cƒ‡±ˆCåúb9çԂÂ'œÐ +¼SÓ½Ø}w{pQ~S‘ß«rIz´¼jaÕtsu~š~BÚ4}„„4ýļœD}•™¯¯l2`Hí‚b6Qï@´FB•ëÒõUf‰é*Œ“Ì!A×Wç'êõÊ yy‰úœ§8^aY‘Fà)þ'G²B>"™‘rçÇÀwÜ"•sÆË›Ü+rL”îC¼"G¬ån<¤^&òmáO}Ú7W’ÕFÝz¦$1àpÀhèÆ©4‚º‘¡,õ狆nÞ¦<ìÚVsÂÂB‚¤N‡T‰ M}wh]d®f=uçü_§œÆ›#Ó_Ÿ_;hº=ºùûò!™2ŽS¾Ž€Xʽ@ödõnPÎc•véUŽŸ}€ªJ¬VˤŸ¸£Ð ß:J¬ò ô-ûIÑe,"¥¢@®ì*úi™p’ofuE!°°zÍCͅ-Ŝ—$Þpix…\\öÅó];<“ ßÎrÊ^øÙ[ÊÝë—诜—8^d)mž—ëH‚óæŒÿ‘âb¦GD,m^‹íbÁ.븢á±|Ëé¿Yi +×\šèAyâw÷ooWÅuaãöÃîéð{;vÅrÜ=ívۍûâc;Û 0¯¯Šëï;úž\ù·«ÿ”qXendstream +endobj +2070 0 obj +2151 +endobj +2071 0 obj<>>>/Annots 299 0 R>>endobj +2072 0 obj<>stream +xÚÕZMoÛ8¼ûWðØ¢ðûã˜&uÛMÜ[/ª£^ØqjÙØýùKò=Y”»6}|›&´ž8ÔãŒ4öϙ`<þ +æ$S–-7³O‹Ùí<0ÉÙâ… ˜uš-ž?,ÚëŽm_Øýömß½íû‹¿fŸ3ÞðX!½ˆôòø%Öi8³Ê4žm˜µM@°fO©úÉ»Wv;×Lˆt¾8÷鄏m¿ïvììiŠÊ›x8oäô<8ŽÕâ¬û}‹Ó֪ёuüwCàGø³yZIâl#EÞÈðvnpÝâ»âp¾NŸÎ¯XQ!– §å`x¨ss¡N(êXߨ“:¡¬ó´ß–ûw ³ò¿\‰æ8¶ãJ]Evº¿Ìül¯âkî!‡à?zÈø|Åî/v‹…Ób8|EÿŒUâ6•'UÂXe~x[îWqïâ¶õ„¯†—%ÑØ€Z¥Žèx +4Žƒf-ïýÝóóïi¾øþ1ÕwšRKJy–³“‰¥±Q6,„Æ @ÊÑpŒqG&ßúöµK…¤£¶ßª³—Ä‹*y´@C­Aïv¯‡ÍàšÚÆÅ Á²J/+`޼M3*è)qòê.*iªÑ³¾šì4·xÌT#gL‘23ýŽí[þ5-ƈIOl-¯ ˜°~|.N⥡Mw¹°@p³ïËpɟdKc´Íå¡{ië2[R„xæï§$ùñë·¿|&L”0Ezx¼›/Ø »ÿöõ‰=m_ö·»Ž}Ým_wífÓízö{ûvh׹半‡Þ8È[W«.音b—ÌÐendstream +endobj +2073 0 obj +1310 +endobj +2074 0 obj<>>>/Annots 347 0 R>>endobj +2075 0 obj<>stream +xÚ՚ËrÛFE÷üŠYÚ Áó~,Kò&©(½ó‘ †)>Œóù™™nMW™£eKR±ê`“hÞ\៙2ÿ*a|ù{ZÏ~™Ï>Ý%¡¥˜¿å’ðÁŠùó‡yÿçjÛñy»Ù›ýîãüïÙí|&;™+”U¾ˆ ;)¼q]k‘RçP¬Äc©þà ƅøtg…Råý‚Îûú¼o~ï»~1”7Ñ¡Óù3æ§:&?F5àµî|†WÒç +é ¡6Ygœ‡a7õ@ÝNŒMB™:[3‹AE•ìjÓÜ »§qùº_n7¥žMyg”->—Ê™Ë|Ju +ÕÄçRiɌqû_¿~]Õ.5‘S—6ù¢Éùë)s+‚ x±ž¼Ça?­B^Gɞ—ÁíµÐõj·-…TÊϽ‡C”-("Ÿªƒ©ÜÜ Âe§tA‚M=^w_†ýïµÉ¿}øö±T *»Ÿ¯³Ñnp¾úU5k¤\»âlÈ-@kЮd9—UBkÁ®®ÇÅa}œmÖ³9‡M<#Á­ê¼EðŒ·âzrt\\˘Ëí`C¨nUíÄÔ6D0+ÎvÜôüªÚ1(Bèø[;ná9fUíÁsì͸ÅgØL5cP„/¯„™Ûq‹O[ð™ºøEø´Ÿá»øoñÕñ€ãÁSº{ãòÿXÆÍY!܎¥˜Žsyܘ«KU1M“ŸÕtÚÜߍ7\ýDj/7„ɳQžH«˜ÂDö«ÿ^¾‹§qŠðå}"ëqÓÂs‘¤M žKüÓ¦¡u$mEó¹bž6µøò ™Ò&P„Ïîi“m8i6~ȉJò ŠX©–ÔHÇåf?Œ»S”§SkœFI2oä,Êwk7uÂ\»)¨‰P'̵Ùi /`¨]Á‹js6Ò¡ÇX»)(Bè1Öæk¤->7Ò +ás–·¶èLšb"ÎÊ·ÆDÇ:°n?+ۏ¥˜®ÛÝåi£µÇË·Tš@û³˜Hë0ÅD¿ö›ÅÍðÒVûSL¤ùø•oôƒ2SN‚ôƒ²üs¢ ¤¹6(B(ßA®Ý T‘æÚ &B™)-º0åÑ +¡ ˜Fó5䟇@ºº&‚ç1nò±òY!܎¥˜²¿lÈʼ|‹¥É- ´³!+‹öѐo7OÛçåfqtä|X|§Mhtƒ±S^‚tƒÁP›³·5æÚuùŠjÞ¡} Nb¨]g ('1Ôæ>>>/Annots 395 0 R>>endobj +2078 0 obj<>stream +xÚ՚ËrÛFE÷üŠYÚ Ãó~,e[ô&®("½ó‘!>JòùL8 W™ÃeGª¢ê +`“gмM\௕`<þ +æ$S–=W¶«÷ëÀ$gÛg&L`Öi¶ýþfÛþ~èØù™}<ŸÆî4o·¬î·+ÞðXazÓÃãçXªáÌ*ÓxvdBˆFdu`›©üÏèwìýZǧŒoÃ*÷¯xÿo{|9tÓë(ßÈø6ã??ÊWØ¥lld<þ‘Ñ'<©¢Ž$›®c?­ƒž +k¨—…òö\êî0œ§R"DýX¦xˆã2ñ±"7LR/¶¢¼I÷ôú2üҞvë¾ë¾½ùöv*j}ãè€FÔp½#L°±cG„ÆdQ:Âudù:´»ÔîÒQj÷›½ŠñXJބ¬¡OGò®ß½gëÐ6. Æ*œ àeñó¦²BpŽƒ_}ꆧ~ÿ2îϧâÎ$«|Æ^|Fd…øŒ—¡ëÇ5>­’Ñ$Ӂ𴟩ûñ\üxQ(oÏ¥ˆúq¸îÇFñdR‚Ë‹*~l”—šýøs7^ìXQiõùGóJK—ü + 9 Ô·ã*WÙ±’'…ø¸Ç¢jÈ5<>nS§N“TÁÓA€a=vãkJpJÒúÂP%t¬&PˆÐy0²#§Êg5xM9 Ÿ5à5dGN•Ïð—©5A <#o8s8‹2y»¤;n®,Q7Z¹|†¨.ªŒ·Çãf3öûÓnž8N“êQé©á„pš6 P7HvEyÞÔSƒÎó"²!}PÃSÁçoFÓ¼UðT<¬’ú¼©z“Ïߦy +zK{ÚÔèœ@a(D÷¡8UùŒ/„g­Ó\æÍ¢PÞ(NW–)M¥ +œ@•‰£¢!¡ÀiïûþÜ£Äɓú@ËJKDº$N PK(E>qªÆÞ㜓B„’Swä7(t…ø¸%:Õød(tUødPÄC§*Ÿ %tð<¿5tšë€'/ +Áö¹QO–×=YZHƅœ, +Tñdi] ¾´ýŸ¿¦NfWö†JKhUi£JൃÑÔݸ†§ +œ@!>͉N5=Þ­·ìûøõaÃ6ççñŸ¶ïØCÞõíñØõûҞ^ÛC:ޱ‰ {ç ý;/âo«ÿ{ ·Üendstream +endobj +2079 0 obj +1183 +endobj +2080 0 obj<>>>/Annots 443 0 R>>endobj +2081 0 obj<>stream +xÚ͚9sG…süŠ ¥€«¹¦D;q™¡R¢¦–,¸pÐ PÖÏ÷Ìt; —ÐÌØ: z\°©h¾§}šfJÈüS ã˯‡Íì—ÅìÃmZŠÅ£P. ¬X|{·XþµîÅîQÜ춇~{Ø¿_ü=û´˜ÉNæ åA•‡ù¯"èN +o\ÅF(¥:…j-îËø³ÏžÄ‡[›ŸX¾`Ðù¹>?7ÅO?–›çu_¾Ž‰ÎÍüÁŽÁëv­;ŸÙ“Ì€@ô‚§M֙ä¾ïÅOç4Ÿ +¯¡Âë8êz½ß•Q*eÍçeò?ÅËoq~™dÊXÏwâåUôJvuñ^ž÷óåþÐ7ëݾÿúîëû27¤¼%LXm¸¼.ù¼¿y!RçPŒ áRÈ:s|Þ/Ÿê¶ëÀiÛ_M~Ìo¥–]BÕÆúF^O/›£sXŸ_ +Œ$œO`eùÛÍ jà‚»úØï†ÕóaµÛVÀ”ŸÌäsþd3 +UÃç˜ _;¦ø¬©>S=Dƒg-Ø mÇÇ9`ǓAxG1µãpَ‘Õ¤”r¯ªÑŽQàR£ÿñÜoOn؀ÚH¬ƒ +Õ«ÀŒ«hÖAEîVLáIƒnU­¸ª†OZp+¶fLàÙú­–ñdIQP#žM +ÌjÞ^†m…3º œÞB’0°™7 ÂÁdøÆ Åç-úL‰P Ÿwà3|ã†âs +ü¥¬&ˆÏéׅÍq +„Íd ^׌£&^Žkx”Õ56¿ßq5ó~ùí·ü»ށ£ä›;³MÄ"h ·%h@4‹ 8稡ën£TC¨tÇûßýžIŒªF ¨Ïä·UsŠ0:¼m+Qª!ŒžwÐPtA5¨†.?‡yÍDñ¹8ÖL <—^[3ç@ÔLáõĹfròrØëÀ¥l]ƒªÆ°1ِìÿÃænõ£_ïǰ±oîZNېÍçÔ1h¶Áö ˜×nì˜@5„ZrÎNb]Y#ÝÔ«$V⌳†"Ô Ëìš5 FB°Êf›6$_H§vH¡jø"¶ÙlӆäóØa—HÑàyì°é´9΁´™ Âë8ŠiÚèËi£6á¶Ü§ƒÓF»³¬ù2¬ýٝ’oŠë ±êð4 šE°Ø†s +Pc^ƒTC¨±g5žÂ»F ¨Oa‰Í9j(B‰M6D”S¯’Ødó‚OÅpꆪ‘OEÞ·5$]€»¦ˆ.`MÍqÍd^?Vá<ƒÆ\å±·&[¨1h”Ç"ü,jÎïkÞܜ%¶ÁB^ÓD³ ËpÎiC¬Ãkڀj ÖálӆÂÓØc×´ÕàiîÉ'Cs8TÃ'#óÃ_²Íـ4í°“c~2€‚‹j<§íuÔ¯=€C fÚ)pUs>àqD ðTÚ$'|ÏÜ÷Ã÷ñÆ9^\8=u¦90mÁ÷ÿ¥¡Ø¬jš%;-Á­æß+x:¶µR>>>/Annots 491 0 R>>endobj +2084 0 obj<>stream +xÚ՚ËrÛFE÷üŠYÚ Ãó~,eÙÌ*UŽDí¼ahˆfÌW@*Éç§1Ý®2G˶\%Õ5¨¦¦yï°9/”ðO‰ …ñbsX|X-Þ/“ÐR¬ž…rIø`Åêë›ÕúÏ}+NÏâþt¼¶Çëåíê¯Å§ÕB6*ôßTÿíá7(ÕHák¢8¥T£HíÅc_þ‡ßè¶âýÒÂû'„?Ï…güôßúpÞ·ýó˜Øhø3á?_ÎWصn<°' ?Pz§ h yl[ñÓ:ůâ=´óBtJÝí/§¾”J …ÛK ·I&À<éCŠð ½’Mn¼ÍËù²jçånß~yóåm_ÔGh6 €nw„K:"5ŽÄÔ.ÐÀòtYos»ëÀ©Ý_ |‡µÔ²I¤ +˜Wò®Û¾ë°nÆ*œOèe²_8T\èWíõ¥;f8£›ðKõ§óè4à(†TAèúÌÇö²évçëîtÌK˜àÁ,(«|Ö Õä4BUðY‹VÃ7qÂm+uFf‰¶_¾,&'uF¡¿ôNúti»ÁEá%xÙ ÑÆÊjªÍÝ4‹b1Uäî¥5oq;Ó/ŠÏ;´›úw¨ƒÜY!ºN¥˜npãmW¶Ná¦Hö;T“-[—Ѿ]¯çûÓæû·†K§¨©Ò&dÏʖŒ¢èö¦\Ԗ,«ßà¢*µ£wb\·¸5¼ü +2U§4:çÌ©šÑkr栚 4®æ95¾èÐlræ *ø¢ç85º Ð_úX@QÀÁCâëg¨ƒ‰3+DשÓÄI·Ǹ˜]*FpSà—ФúȹÿÖn¾yã4·¼é¿¼¬ô„uÙ³ræ (zÌ×2Ϝ* x¬3UAh mŽ˜fN^[rÌTž–̧Ê'iމ#ÝÜ´$¹Ù&NO§i<­HM|:ÑpšmæTùΧs0 (ð"§ë™3ÔÁ̙ÂëC)ž™sã6åÌÑޏoâ4©)t´§áv}»î–»vÿõ2DO°¬ZBUZ™iò„¢h Ç>pjx†Ý9pP|–Ýl§†§iʝU§iÊÍ9rj„ŠæÜ9rP„ŠæÜ|#§Æ'åè5ŠTÁ'iÐÍ7r*|*Òd»ÏžŠ¯|“3TÁÀ™•¡ëŒßâܸE9nTÀé8¼Áu$¦´Q†ã˜6§Ëø‰±MlljF«+ áqRžEÑžåœ#§hiTž#UAhiTÎ6rjx†&Ü9rPx†æÛœ#§F¨iȝ#UA¨yOÕªt2ǘPt22?ªTãKv:©”æ3íä^{N‰Š`ܔUðªã|HéÆ Êqq.ž,T³J‘†â9kNÇc»¹ŽàHviãMåÐZœN(ùùpÜ'öç“jtΕǓæ³qÇú“›™UÅa;Œ[Íþ¨@ OÇ⤀Ž?Œ˜˜Ÿ@¸‰LŽç]#wµ°>ÑüçãÃÝr%މû§Ïâñô|ýwݵâswÚvëáí.â÷õñe½Ïëèzo}pJúÏnG·ñÅÿèתÃendstream +endobj +2085 0 obj +1225 +endobj +2086 0 obj<>>>/Annots 539 0 R>>endobj +2087 0 obj<>stream +xÚ՚KsÓX…÷þw ‹ˆû~,3°š*H̎'(ÁS~ddgàçsïí–u•*Ü^6@9uÒαÚç“;ýßB ™ÿ*a|ù÷°]üµ\¼»MBK±|Ê%áƒËoo–«6½Ø?Š÷ûݱßo—ÿ.n– ÙÉ\¡<¨òp÷QÝIáë¢Ø +¥T§PmÄ})ÿê;†'ñîÖæËÏõùÜüŒ7?WÛçM_žÇÄNç3ÿgÇà7„w­;Ÿ½'™¿€@ëŞ6Yg'÷}/~[§ùVx í¼ÇRכþ”R)ë?áeʗ8¿L2e[ٞt'…ör+z%»ÚxߏÇçýÃþ[ïí×7_ߖ¢>æac4[µç;Â%Ÿ8wDꊩ#\ +Yg/_«§Úî:pj÷‹ F“óµÔ²K¨‡±^Éëáée;F‡õù¥àá‘4çd™,Tc.HÈ«»þø2ìª9£»ðGõ§ó49Q ªÆ¡ 3úÃð~>®÷»z S>™…Kҟ55•F ÖBÔð%åÏHȗ‚=£ _hâŒu€8³BxK1%Ž=O§BM©˜Êû¸Š 8NÅ 7›þ؏°qš[W¯Žh ijhrªhZBZÈ,ÎÈ! Úڑ#r@MmRxoÄ:”½ðî¨@Tc/Dˆ,ÎСz aS¡ªqèD _èPþœ‚{¢ +P?§y#‡rgäKy߁h̙ùB#g¬șÂãXŠ)rÜyäXm!¥d¹Ç51Çj)U¨s³{õ!dz +d¨¢i¥!¯8‡0hRļ*À594)á­WàPö¢ƒ¸ªÀÕØ‹ž;n(AAÐT܀jüås"oÜPþ\ç£í¨¹/æ|œvü|¨íÓ¥›XWÕ⫽±SÔ$bmã±n@¸ùҀo(s8}´±,!$õœicÀÎÇãV³ß Ü騬 èøjÒÄ{Y¼MÆäiq6Ž‹³ùgõiœ&Ý]ß.ŕxÿåÓ½¸ß?¬†^|öOÃj»í‡ƒø{µ{YmJÑ+¥½¸ +0)ý½^ã«øyñ ó ¶Uendstream +endobj +2088 0 obj +1213 +endobj +2089 0 obj<>>>/Annots 587 0 R>>endobj +2090 0 obj<>stream +xÚ՚KoÛV…÷úw™,ÂÜ÷céÆqZ ES[Ùe£&´¢BWbР¿¾÷Þ’ÃÑõrj‚(|¨ÑùÌÑü½RBæo%‚ƋO‡ÕOëÕë»$´ëG¡\>X±þüb½ùsߋӣxs:ýq¸¼\ÿµz»^ÉNæ +åF•›ûw¹T'…7®‹â ”ôFµ¥üw¿qފ×wV(Už0”ÇúüØüŒ÷ýðõ|¬ÏctòŸ™ïìX|Ùp¯uç‹{m:ƒ +݇ù^_ÌÜö—OçÝÓ°;K=›òƒY¸lú“©³ÅŸRBEü)Ù՞yûmsxÚ÷õŒ¹ ؼ‚-.•®=ˆ$ó b¶çRÈ:;yè{ñÃ:äWá<Ùe!<Ž¥nö—S)¥R¾÷ÿpšò›4Ÿ¦hòmis;)´—ÃÄÅÚ_†áé]?Ün†þa8ïŽÛ/>¾,u£ãÒA5ÚÁ§f)ui‡ !¯>\6ÛÚë:pêõgtóJv qèäÕÍyûõ0f¿õùdðpÙ´g ÄU…(bÏZˆ+ÎÀi94‚¦qhÄ _à´ü©ISŠøS‘7nZ|©L¨‚˜“òå¸Á:ˆZc)¦¸Q×qc« H)ƒjƍM +RŠg½;ôn4Ÿ¼Ò×ûÁ†PóªòÄÜ6Dˆ+μiôãªðqèþWĕ7-{NAZUހ"öœæN›–? g*m@9|#oÚ´üåÿgýDPğv4|yÓòWù€¼Aì) ùÒæÍXx³(„DZSÞèë¼1)ÂU`Ì!bƍÉᬠnîvýþóÈ/ÙdÕdÖ\ï “/ÇäÈsO˜è¹§e/(Œ¬BPÄ_~LdMœ–=!±*q@{.AbqfNË¡u5•9 ˆÃüZYÞÌiùË/ˆž˜Šø3҆/sZþröˑ9 ˆ=-ŸGœ± +gQŽC!¦¼1 ÞÈqfJK23/À‘8Gàüڷ׉8‘ÙÛÙ^o`B^qbnp@Î8-ƒGä8 ˆÃˆ#r¶ÀiÙó8Ù®ÀEìyœksNË¡‡Û8 ˆCÇ7-w&M£"…Џ³8Óæ‹›–? íJĞƁv8c΢gã<‘c¯#G+˜ŒG“ßœ fâh…ƒñBœŸûÍtyc ‰x]ހ[×h + Sr€Ž\ɵÄ!9gè4 ªˆcò +P³Cy_ã´ÌCV +@sÁò_h9ô’¬ €"½â¾6ÐògYEüÙÈ}m åÏØym±gÜsׯ:E!<îX¯ ¸ëÐQZÍ£&3t”ž¦j¿wÃn³ßý;}†ã —VŸ¼úFKÈ0¯€ -!#ÿՁ†ÁdÉæ@ZNʓc¾7ÐðYˆË1yÔü—ö|$;>.ÒÊ'î¾µÒB–ãlÇüãßúøfÞ°ËA¶ÕÏÝÀ"ãG7ßm +Œu˜Æ7®j`žãÇÀÏäš&ÍK¿×¶¾ŒpqßUMå/›mÊic6âÆlû„ã¤Ûû›»µx%Þ|xÿ NÃ?›s/ޟOÛóæpèÏñÛæøu³¯MïL~k¼ +02Ý}ÃsúÇê?Tºûendstream +endobj +2091 0 obj +1227 +endobj +2092 0 obj<>>>/Annots 635 0 R>>endobj +2093 0 obj<>stream +xÚ՚MoÛF†ïú{Lföûãè&qO\[¹åÂ:´ã@.%£ùùÝÝY’ÃÕø8¯)¯üËy¬Ñü½QBæ/%Œ/ÿö›ß¶›7Ih)¶B¹$|°bûíݶÿk7ˆã£øx<œ‡Ãùô~ûcóy»‘Ì+”Uî~AwRxãº(ö"¥Îµ°÷eõ_~`|n¬Pª¼^Ðù¹>?7¿à—Sÿ4”Ñ¡ÓùwÌßê˜ü €×ºó^iÙ¥–}!Ô&çŒs=>½î§Si}>Q<(I<™:[ð¤ÏWÂS²«;æn8¿Ž‡ +gt8]BŠÐ¥BV. éLK ¡KeGf˜OÃéa|~9?õ¦üd”$_4ù1ó)Õ©–_¬×ïóÏ~ÿ²«· ‰œnA’Î'¨=2ßg\P_î‡Aüç:èGá,ÙõBp|Zêzw:–¥TÊßý?œ¦\cóir¾V©Pî_.›À¹Eêûùür{<¿¾ûú¾nrÅ­ϼ‘ØÖÔ²U•m k¡jqÖhd«ZE;¡QPµØj‡ÂSŠVÕ$„§"wéP|Ò@¹éԄø¤…bÃW:Ÿ­Es’¤…Ï&‡¯v(¾ ¾0/D¨/´v¦u@;«…Úñ¶SíÄËÚ±ÞÖ*]®<íXï HUíŒÏ‡óã,žÄ¦R­p±+œªU«ZÚNsw…gB+ZÅ9_¾ƒ#kçPxÚBͪ΁„𴃚ÅÙ:a­2“u !B¥¡ÖðµÁgR„?Šªu -|&ߖš·u(¾\Gåd/ú·9gZœ³Z¦÷Œ“.ÇUkTpeÔ°Çä³gã¼Îïsò.p<ßçtQ[ÂÅZ´ªr  -áÔ,ÆÒ!­k5«H"Ì~±œ¥Câe‡èY:ž1P²K‡$ÌDÎҁ„µd­’Nº¹o¤ZBt²5¸Ù*‡âÓ ÚÛÕ <Zw›–δHgµP;>5ÊYjçÂiªÚÑÚäµ» +aюŽ­K^´s7ôßæ·9ew0ôNTĦðÐ2¯Ò€6…osÎÒ¡]ë™Wé@B„Ž·r(8ÓZÝU9œmnÎÊ¡µoŸÉå@B„ºµ»ùJ‡âSfî©–Ÿjím¾Ò¡ø$4·Á rÝÛÖ²õ¶ß ¶N“^¨ŸÚä<¥£.KGÅ¥IžZZ¬£b\œóp<†‡ù Ình}yC¨`– ˆPÁ²Ÿ" ½DS¡W¼§H<Ð$„g#û)’ÐX4E Ç|Š€äÓ +M@B|šwc¤“a™"€€àd|ëÁ´gµP;9O\8MU8 ä)æ]›ìj† ¹e„à~xéÇþ<̶‘ìÚkÑ\ÞQ-ãqÝ&šýðEç#šðë.¹O¼'(6çðàÀºECÁY…¦¬Zþ¦™Ï Pp:¢‘é41¸…LÎó®±Í»*—÷šO­ôéîúf+®ÄÇ/·÷âþøxþ§q;ŸÆ~¿Ɠø£?¼ö»²ê•Ò^\è”þl'ñÏÍ¿6Ũcendstream +endobj +2094 0 obj +1188 +endobj +2095 0 obj<>>>/Annots 683 0 R>>endobj +2096 0 obj<>stream +xÚ͚KoÛH €ïþslUçý8¦M³§º‰ƒ½ô¢•Ô…_k;ØþüRÖ¨@ÍÙ9´?‹âgÑüw¡„Ìÿ•Z/ž¶‹OËÅÇ»$´Ëg¡\>X±\½[öÿl±Ÿ÷»ó°;ŸÞ/,¾,²“9Cù¡Êû?rªN +o\ÅV$Ùy 6â¡dÿåŽ/âãJ•ç˯Ÿ›ŸðaÄoŸ£I»Í«:;<Ž©n6§}I¥Rþ­,¿éü‹æ·xù…ç·Pëüró[:…Òå3åµÉq&ù~>†óÝzج¾½ûö¾äô²s|8Öõ"S>‡6å—–šP²«Eøxê_†’H‡Nó"¤]òù%çbÕ²KM„. RªÇ—×íxyYÏæ<’xÑäŸO0ˆ¼XOßýp~=î*šÑ]àtI>Ÿ ×äëÎ`Ôð æv8=ׇóz¿«'0å³ $ùœ¯Í¦ôR…QÃçt›/?ûíaS/A9]‚$Ÿ5Ð_Š hð¬…þB;gÌΙ%Â㘊©sìuç8#k—Š.w&ç8£ Iç,ýÓ0 +ÇÑòà:¢*T¨]«Z‚¦*Täî +OlZÕ95jø¤ÅG\CàÙzō΁h³IAÏâlŠ0è6Õ:5„!B¯ákŠÏ[øPT­QÃçô¾Ö¡øœ‚þRJ‚Ïé·9gÌΙ¥Á㚱qÜuãXàFQ—k¸“ql>Ýq4Îãa՟/ÊqŽp¢'ªA[¸¡+¶ ©í ]qö X tô D ¡ÒøÑˆ«o<“"t«êˆ&<“O«æîŠ0î“ß@ÔFÏÛ6]P—y‘¨¡Ë‰¼mCñ¹ý¥H‚Ï%è/´oÆ<à›Y"<Ž©˜Ç_7ޱ®v©zÁd“û‘ó÷q}nïqË{œ@T…ѵkUë@ÐT…1д8[‡Ìå'/ց¨!Ԓµs(8‰3npŽtóž%qÂÍÙ9¡N0æç@4ê„sn¾Ö¡øBºLŒF _ÄÑ6_ëP|ÛU 4xçÚ´uÆ<`Y"<>ŽÈyZ'\·Žv8 WæMÚÑ®Áúp¸Y­>í÷›¡ßâ –U9D¢ Ê«n hÊÁ✜³n(@“òªˆB“r¶Â¡ð¸«p jðŽ·9 ‡"”¿‰«Â‘rÞ±$¹ù +‡àS1\ÆE +£‰OEæ79]0Ób \°o]ó€nf‰ð¸e½<¯ëFyœ«ë¢I7Êãl|&œÓÅ8‰Ï×91õ`ô8AS6ò_ m jc¾8@áiÕ,@Ôàiö#5ŠO†fq¢†OFî‹_²ÍÞ@šÏ´“ã¾5@ÀE5- Äù4;ê·® `M›ŽjÖû‰ØQƒ‰8¬¨ÅÙ¶€Çq8(æ¶ùê†ázZ’ÔzL³'0ŸŠ;îßÚPlV5Kv>·š÷ŠÅ¦c³! ã/£%öû€7±ÉËÆlčY]îV|Â!ÒíýÍÝR|Ÿ¿>ˆ‡ýóù¿þ8ˆ¯Çý˱ßn‡ãIüÙï^ûMeu&_´ÌG®ñükñ?Hä·wendstream +endobj +2097 0 obj +1218 +endobj +2098 0 obj<>>>/Annots 731 0 R>>endobj +2099 0 obj<>stream +xÚ՚KoÛV…÷úw™,ÌÜ÷cé&qÑEÔVvÙ°1-¨Ð«’Œæç÷Þ;CñÒ@5Úu’Ž)òQÃsÄÑü½PBæ¿J_þ}ß.~Y.><$¡¥X¾å’ðÁŠåó»eÿçfûñq¿;»óéýò¯ÅçåBv2W(ª<<þ*‚î¤ðÆuQl…Ò¦3¨6⩔óǕøð`…RåƒÎÏõù¹ù? §ïÇõá¼ÞïÊkٔ Ér ûŸÿ$I°kÝù®T§P!{áËgÄŒÏ?úía3”Z&všÛM|2u6ó%™A@4xJvµaž†AügæWá<Ùy!8>–ºßœö¥”Jù§?ÃiÊ-,…K>¿«O†Î¡B¼|©¹²Î(ëÃáþùù·|Q­†ã·wßޗª>vifU×[ÂE“sK¤‚ZÅÔ.Öwñë©_ÕnׁS·ß„纙쪆/Hp¬ûãêu;z£õùTð $ñœÒ¥GA5x.€a=ç×ã®Âý“õ§5`55Ž@5„Ö‚ÑðŠÏHðš9 >£ÀkøFŧøKÉ žŠ·ÎXgVGÆq£ˆ¸‘<*ÃETMÜH 5‹›Ó˜7Á²ê}½l}·0m@LÝ`“»âœ7`hW%o@5„!âç"®yCáy‹ŸŒJހjð¼·âœ7¡Sà45o@5„NóNŠÎ„‹Õ(T ]Ž–È;m(>mÁ_г€hð´¡óf¬y3+„DZÓÄÑ×ÇV¬r—O ¦Ä±JƒKAâ<ö»Õp¹½ñ¬ü8™ëý`R¬~UóÄÔ&ÿTsÏ +0:´«’7 ÂèY§ ¸UMP \~Näž6¡‹à35m@5„.Ëð͊ϺˠH¡jør/ZÞyCñå†ÓcހhðŒ¡óf¬y3+„DZÓ¼1×óÆäÿnu)Y¦c ¦¼1Z¾I›éîF±1«Êi‰v0;‡¸‘nîWÇãœã†Ô ä5n@M„:လmàPxçÚ5p@5x§Úœ‡"ô8Ú®ª!ô8Úæ8Ÿ3—A‘BÕð9æqCјf×LÑÀYfÓq3ց¸™‚ãc)¦qc¯ÇÖ8Ï÷m£šâFkœŠcà §ýæµtú:1²@MŽh“ñ6 šfP8ç6 ÄÑ8„œÆµÄÑ8Û°!ðTęv PžŠìïm(¾`šEP _°Ü—(>/›eP ŸWܗ(>¦e ž·. Œu lf…ðxd½,இ28×±´¹±³ee\»,0…Íå'•¨e@›<ÑZM‹ švÐìiž Í¢¨†OFæ‹^²Íž@šÏœã¿%@àEÕ, D5³ª¨¹¯p>6~>Ãö‰û~€§6Xšõ€ùôÚÝøe –ÀÝ÷v5€ó÷4žúžoÓbùº\Íö¬nמ†CìÏûËZH|®àˆúqZ +ÐñÍH‰ÿJ@¥›Ðäe76ânl¾ ùJÅéѧÇû‡¥¸¿~yOû—ó?ýq_ŽûÕ±ßn‡ãIüÞï^ûM©z§´w¤?Ök<,þË ¸Eendstream +endobj +2100 0 obj +1212 +endobj +2101 0 obj<>>>/Annots 779 0 R>>endobj +2102 0 obj<>stream +xÚ՚KoG €ïúsLÙÌûqTî¥R[¹å¢ÄkE…®´Fóó;3äj¹¢Ñ­¬  V¦ôíRü$š/”ùW‰ …ñâÛ~ñnµx{—„–bõ$”KÂ+V¯V믻^ŸÄûãaèÃùõê¯ÅÇÕBv2g(7ªÜÜÿ–SuRxãº(öBiÙ%Œv⡤ÿé/NñöÎ +¥Êæ—áÏÍϸ¥:…ÑÄçRÈqÆøøc½Þõõ +Æ|›+Øä‹&ßîE’¹! x±^¼‡¾¿ÌBþ§Áã5Ñrw>–D*åûþ§(÷Ÿ|Š|‚þ%M¾²!\î“.HèQÛççåããÃpÚ6_^}y]’zÏé½Ü¥Ø(çk»J)wXH1¸Ýêóy½©•®§J¿ ÐìVEEBk¡[±ÕM ÏHhVU7<£ YqÖM‹Ph4U7By˦E—;LœdS#B'-t¾²iðÙ*” žM +úK[7cÐÍ,ÇTL…¯ dž]J†Üz š„cC„.E…s›nUQS£"¼­«RÞAÃâlœ SذŠq "„N³öM ÎüdT|ËÍ)r÷M‹P[è4Õ7Bí Ïð5N‹¯vÐÑ8>¥¡Õð5NƒÏ¤ý¥h‚ Ï䮣o3ΘŒ3K„Ç1Sã¤ëÆ1Ñá÷·2‘€h2މ}óa=ô«ãj»ï/¾áòvVR6J!«1Žª€”B~Hd­š6Ÿ‹ØªŠi "€.áG"–®iÓY‡Ÿ‰Šj "tIJVM0¿^}1 DÐè/LMÓÆË Q^DÁӒ±fÚp&Ü éæ­EâûË`´ M„ÇÇy8CË\;KU2:Á0<ú\LŽÑ gáÅ2ý®.†±‰Õ7šV]/ `.^mÁT:âXœ±mZ|çâÕ6@sq®¶iÑ9œgWÛ@Dèw×´ð N´«k "x'Úl]ÓÂÓþ2R<sl¶¶iá)bW%@@èΰ۶ó€mf‰ðø8giÕ°ÄY¸ +¥Æ%™…ÝHœ…gÝÜmËa8m¿¾LÖ å=Á‚UI}½T„™xU S=¨ÈýkM‹.²=Á –ó†@›ÎK² ¡óŠù‚@в´‘õ~@ÏX²Á3Žõz@O«i;B§ožY@4³4x\óՌ¾®™ò?šÒžb,ÍW†Ùn€’ñ²ð{Ø ßG½8ÍeBLYÍõjHvÚHóIxrÌwšpQ‘Í€8ŸƒGÍy/ ‰æ#Ù +ðó¸OÌwštÎэ7_ð¬åbZÿœ!Ûv>°¶šõ.@“MÇi@ÏGÕ:ݺ€Ið Lüi `ÌÃÓ+õüL\ò²ÿqÿU¹ü6ôi\ ¼_Þ­Äñþó§ñp|þYŸzñétܜÖû}:‹?և—õ®‚-•ð&ÀPõÇv»ÅÓøçâ_¯° endstream +endobj +2103 0 obj +1222 +endobj +2104 0 obj<>>>/Annots 827 0 R>>endobj +2105 0 obj<>stream +xÚ՚MSG†ïús´¬çûãHÀ䔹rñE…RJ_Y‰Ø??3Ó½ÚYWYͱ”T/+µxgzûÙmúŸ…2+a|ùyÚ.~Y.>Ý%¡¥X¾å’ðÁŠåó‡åê¯M/ö/âf¿;õ»ÓñãòïÅçåBv2G(ª<<üšãtRxãº(¶"ÄN£ØˆÇý‡7 ¯âӝJ•ÏË‚ÏoåׇÃïý·¯¾~,ŸdUŽ#Ëï;V_Jڟ.DÐe!´î|^ˆ”:‡"ä…Ñ&ëlêËqõڗ@:ðòIû“©³ÙŸÒ²K¨ƒJv5}®‡×·í˜6Öçµà`’tç’Ïû‘ÝÉò jrçRÙ­lã¡?½ »êÍè.ðÙ@Ú`4ù±lŸé ªÆ`¬›wÛŸ†õá´Þïêö¥üRis>Õ"¤”êªÆ\Pi>_m›zú™Èçô£í9¥Eæ'; ´<ö½øiœæ­°Lvc¨ëÍq_B©”õÿ`•*‰œ5µ@—OLh.ÓÆY õ)Óæ~?œFÜ䨌q6³@xCñ„¿ ã"Þº•F¨‰6Æ%(P™7Ëõ¶_îoW§~¤Nàr*+ˆ\°®ªŠM.ä‚k™c†ò—ëª>cTcмbŠÊ]>£ä3 wZ2‡ eOB§!#ݼRIlg³… aO'}n)T“=°Í3”½íëʍ»ˆÝk3cÀÌ,CñÄL¸Œí¡ Ë%!ˆ‰2Úc>>>/Annots 875 0 R>>endobj +2108 0 obj<>stream +xÚ՚MsÛF †ïú{Laöûãè8V§‡LS[¹åÂZ´£V_•ä6?¿Ë(.=A· öŒ<¯)Az¸ ^‹¿gJÈü«DÐÂxñ¸™}XÌÞϓÐR,ž„rIø`ÅbùfÑþ±îÄîIÜî¶§n{:¾]ü9»[Ìd#s„þAõ÷¿äPÞ¸&ŠPJ5 +ÕZ<ôá_½âð,ÞÏm~bÿ†ùcxãósó;Þ}o7ûu׿‰Î3ÿ³ùé?JI]ëÆgô$óHÞÓi“uyè:ñÃ8ÕKáÚi <Ž¡nÖÇ]J¥¬ÿg)/p>K2eª|–t^m—óÐ+ٔ¬Û/—w›Õi¾üúæëÛ> s\Ï êr:¸äsòfÐÔ8c:¸²Î<_ŽísIuø¤úu|Ñäǜ¦Z6 UË:Þž_6CÕ°¾á±Š4›OPÅd¿l *¶ ¡RÝw§—ö°Ý>ËG:5&׃ªt*ÌÇîøxXíO«Ý¶,`ÊOfIãYSŠ ¸¨ +ÏZ¨2l†Â3JKo *:£ ´ÐN3ħ™ÂãЧӍËNãT(*ö F§qª\Áû}ñ™Áe¬eæ2ª‰t¦T+pš"ªtŠc§!ølIÆÁi@€6)ü:ÄÔk(º V¯UхµŠ±×P€ÞB•)^ªôj [¯¡ðœ‚ïAÅk@UxN³v +Î(-ý5¢bË(ñ:§â€ÓLáq ÅÓiôe§±ÚžïØ4ªÑj¬vP ²ÙÌWÛåí·Ýê±,'XNé`ˆt(ˇN¢J¥¡T1v‚Ϥˆ¥ªwP# Éؚ³ÓPtÑA¥*Nª¢‹ž¹ÏPxAA)>ªÂ * [Ÿ¡ð\<…ªÂs Š [§¡ð¬ƒÒÒÛˆŠ._dö:§â€ÓLáq ÅÓiÌe§1ùš,ªpÆ +æS{ø«{å7Jþ䢬”%2!¯ˆLD• Z2·ŠNbƒ,Fºi•’Øçj1NØ».j¤Ó ;׌M† о“UFì_³5 +ÏûsGH¡ªðªTØçê3ÄÎ5øŒœ¶ÀµÄ¾5cŸ!U ¸»Öû ¨PEÞ·2\0Ր¨ +.X惞—ã ˆŠÎ«k†8à3“@x\qp—FÙ¡ï­Ïjte±ïæ×#ÜÈ >㠏<Q=‘Ǝ£ ª„0Žý(ŧU5 +ªÔ¬›f› Õ(¨ŠMFö£`²Õ$@²“b•ó9‚-ªj NÛÕQ3 Ø|gü´QíÓµGÍâ«ýÿ!OñÄö¿«Ç“Üt÷؏éåc÷Ô¾¬OÇÁ^rbp©MÚŽ÷ýí´Ým5û]NÇjÓ_ÇW$Þ[þmä’çy×8Ì»æêÓÐ,º¿™/Ä;qûåóƒxØ=þmø|Ø=Úͦ;ŧvûÒ®K‰rR¼ ÐýþžÁßgÿ„«Kendstream +endobj +2109 0 obj +1217 +endobj +2110 0 obj<>>>/Annots 923 0 R>>endobj +2111 0 obj<>stream +xÚ՚KsW…÷üŠ»´ß÷c©ØV6qY‘peã ±F›W%®üúÜ{»‡éqU¸,;–‹ªÃ@Ã74ç@ÓĐùO ãËÿ/›ÙOóٛ»$´óg¡\>X1z5_ü¾îÅîY¼ÝmOýöt|=ÿ:{?ŸÉNæ +åB•‹‡ŸEНÞ¸.ŠPÒwÕZ<–ò?Üã°oî¬Pª<`(·õù¶ùúÓËa[Çè.䧙¯ìüS*4àµî|×¦3¨¾æk}ay׿VûÓj·-õlÊ7fÙÆ“©³O©N¡"xJvµcÞ_löë¾¾~17“ׯ‰çRiٍH2¿L F:—BÖä±ïÅÖ!w…Ód§…ð8–º]w¥”JùÚÿÁYÊoÐ|–¢É—…Îf +PH—ÄÅÚûýӇÅáÛÇÚãŸ_}~]j.oe¥b£|ª&–RçPN|êÓq±¬]®Ÿ.¿ŽÏyô)Ù%TÐð©ÛÃòe3X¾õù\p€lÓY6U#¡³lŠqÌ´ƒ©1ŠöÂ6fZx* Ã”˜EðTd2-8iÀZjTAؤk¹"d°† -„DZϐ‰—CÆV†|–\îYcÆØ¤ÀŸrÊ|Ü÷Û»§!a²qENF\HÓå~°!T³ªQbì"xã¨iñy‹^U¢ô? +1šS`U5j@:§™M Ï0™4 ^6ÞÈ:hZxÚÂÇ 4 žv`3l£¦…W££¡S¬¥5CˆšI!<Ž¥xFMº5&E0(Y>փ³Æd_Ö4kVë~Ho˜y±–—ÂDWݪf ˆ±!Lô¼“¦IšUIP/ß&2Nš&‹àU5i@:—À«øfMÐ:p™š5 `~¥,ç¬iâå—CŸ³Á3l†kÖ4ñ²çË!k@:-¯Kš¡ +$ͤ ‡B,sæÂ‚œ‘0&¿-A˜‘8ûƘ"Æzn_h€U]î`^ƒÄØ :áœqÔ´øÂkԀ"€á\£¦Eçq~]£¡ó8½f5-@‡#ì5  ã4-8“΃!…ŠÀY^³ šž†ÑuÍ„Nãäº5CˆšI!<> ÁY†º6Zá¼~55¦V8ÏisŸ=ø—~»<ýqþ™ÆòètՍv0 +‡¤‘ÓI¸–8 gœ4 >q^“Ô¨"ë¯4-¶`Ȫ(Â,÷u€& —dôŠ÷:@ϲŠàÙÈ{ ‰g츂Ðwí:ÀP’fR;ÆëÎRMšE8/Þ jLš|w’3«ÏL£dw@v‘ûN@‹/Y²¦£ðäX/´Ð¢"ûq:šû6@‹ÎG² àãĦ|â½ +ÐbsŽnL֎õ3-2«Æ5;U[}í~˜ùa`¨Ã3WLãÌ0îŽùͨãd@§óïÿ%V~[=‘o/Љ+¥-ÏiD”çÅ׈‹¯*æçëNŒÞ=ÜÞÍōxûéþQ<îžO/½¸?얇ÅfÓŽâÃbû²X—ª7J{q`$úý¯žÏ_gÿz~¬Õendstream +endobj +2112 0 obj +1224 +endobj +2113 0 obj<>>>/Annots 930 0 R>>endobj +2114 0 obj<>stream +xÚ͔Knƒ0†÷œb–í"ŽÇƒ—ištU) ä4uÔ6ÇïH“VªØ‚%Kcìßþæõá!p¡©`_z‰7_k’` A…>$owIúZ¨°¬«ÖTmsŸ¼{«Ä㌓‚›ÐMÛ'’b” X%h͂Á( vêØ ækÝ}ô +%í¥ wMšw‰™ 7қćÂa‚)bGÁ™¬Þ +I6Ñ,lv*/žôùi +ãt\3ßÑqEqé­:ä¬Ë—­iO¶êؤ`át8 +hæÂ'™¬+` ]:Ë£iö6?¶y]uÔ´yãx‘¤™ðÖ ^ÔEouNËcѕŸŒ¦S~ãpJ÷m‡SõÆ [ÈûÖÿêÜíäÿêÿ_¤ES;)Ô´:-/]ÑøO£†F‹•$RÎö©¼]¬˜Ár·‰!®íWj llÙ´,mà9­NiÑ¥ƒPÚÌBÑÁž?ó|ðä‹÷ ˜Hendstream +endobj +2115 0 obj +384 +endobj +2116 0 obj<>>>>>endobj +2117 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS042S072PIÑp rt QÐUp VÎO+)O,JU(ÊO/JÌÍM-*VðMÌ+MÌÑ ÉâÒéӅj¬(ËÌ̉º†prJ++endstream +endobj +2118 0 obj +109 +endobj +2119 0 obj<>endobj +2120 0 obj<>endobj +2121 0 obj<>endobj +2122 0 obj<>endobj +2123 0 obj<>endobj +2124 0 obj<>endobj +2125 0 obj<>endobj +2126 0 obj<>endobj +2127 0 obj<>endobj +2128 0 obj<>endobj +2129 0 obj<>endobj +2130 0 obj<>endobj +2131 0 obj<>endobj +2132 0 obj<>endobj +2133 0 obj<>endobj +2134 0 obj<>endobj +2135 0 obj<>endobj +2136 0 obj<>endobj +2137 0 obj<>endobj +2138 0 obj<>endobj +2139 0 obj<>endobj +2140 0 obj<>endobj +2141 0 obj<>endobj +2142 0 obj<>endobj +2143 0 obj<>endobj +2144 0 obj<>endobj +2145 0 obj<>endobj +2146 0 obj<>endobj +2147 0 obj<>endobj +2148 0 obj<>endobj +2149 0 obj<>endobj +2150 0 obj<>endobj +2151 0 obj<>endobj +2152 0 obj<>endobj +2153 0 obj<>endobj +2154 0 obj<>endobj +2155 0 obj<>endobj +2156 0 obj<>endobj +2157 0 obj<>endobj +2158 0 obj<>endobj +2159 0 obj<>endobj +2160 0 obj<>endobj +2161 0 obj<>endobj +2162 0 obj<>endobj +2163 0 obj<>endobj +2164 0 obj<>endobj +2165 0 obj<>endobj +2166 0 obj<>endobj +2167 0 obj<>endobj +2168 0 obj<>endobj +2169 0 obj<>endobj +2170 0 obj<>endobj +2171 0 obj<>endobj +2172 0 obj<>endobj +2173 0 obj<>endobj +2174 0 obj<>endobj +2175 0 obj<>endobj +2176 0 obj<>endobj +2177 0 obj<>endobj +2178 0 obj<>endobj +2179 0 obj<>endobj +2180 0 obj<>endobj +2181 0 obj<>endobj +2182 0 obj<>endobj +2183 0 obj<>endobj +2184 0 obj<>endobj +2185 0 obj<>endobj +2186 0 obj<>endobj +2187 0 obj<>endobj +2188 0 obj<>endobj +2189 0 obj<>endobj +2190 0 obj<>endobj +2191 0 obj<>endobj +2192 0 obj<>endobj +2193 0 obj<>endobj +2194 0 obj<>endobj +2195 0 obj<>endobj +2196 0 obj<>endobj +2197 0 obj<>endobj +2198 0 obj<>endobj +2199 0 obj<>endobj +2200 0 obj<>endobj +2201 0 obj<>endobj +2202 0 obj<>endobj +2203 0 obj<>endobj +2204 0 obj<>endobj +2205 0 obj<>endobj +2206 0 obj<>endobj +2207 0 obj<>endobj +2208 0 obj<>endobj +2209 0 obj<>endobj +2210 0 obj<>endobj +2211 0 obj<>endobj +2212 0 obj<>endobj +2213 0 obj<>endobj +2214 0 obj<>endobj +2215 0 obj<>endobj +2216 0 obj<>endobj +2217 0 obj<>endobj +2218 0 obj<>endobj +2219 0 obj<>endobj +2220 0 obj<>endobj +2221 0 obj<>endobj +2222 0 obj<>endobj +2223 0 obj<>endobj +2224 0 obj<>endobj +2225 0 obj<>endobj +2226 0 obj<>endobj +2227 0 obj<>endobj +2228 0 obj<>endobj +2229 0 obj<>endobj +2230 0 obj<>endobj +2231 0 obj<>endobj +2232 0 obj<>endobj +2233 0 obj<>endobj +2234 0 obj<>endobj +2235 0 obj<>endobj +2236 0 obj<>endobj +2237 0 obj<>endobj +2238 0 obj<>endobj +2239 0 obj<>endobj +2240 0 obj<>endobj +2241 0 obj<>endobj +2242 0 obj<>endobj +2243 0 obj<>endobj +2244 0 obj<>endobj +2245 0 obj<>endobj +2246 0 obj<>endobj +2247 0 obj<>endobj +2248 0 obj<>endobj +2249 0 obj<>endobj +2250 0 obj<>endobj +2251 0 obj<>endobj +2252 0 obj<>endobj +2253 0 obj<>endobj +2254 0 obj<>endobj +2255 0 obj<>endobj +2256 0 obj<>endobj +2257 0 obj<>endobj +2258 0 obj<>endobj +2259 0 obj<>endobj +2260 0 obj<>endobj +2261 0 obj<>endobj +2262 0 obj<>endobj +2263 0 obj<>endobj +2264 0 obj<>endobj +2265 0 obj<>endobj +2266 0 obj<>endobj +2267 0 obj<>endobj +2268 0 obj<>endobj +2269 0 obj<>endobj +2270 0 obj<>endobj +2271 0 obj<>endobj +2272 0 obj<>endobj +2273 0 obj<>endobj +2274 0 obj<>endobj +2275 0 obj<>endobj +2276 0 obj<>endobj +2277 0 obj<>endobj +2278 0 obj<>endobj +2279 0 obj<>endobj +2280 0 obj<>endobj +2281 0 obj<>endobj +2282 0 obj<>endobj +2283 0 obj<>endobj +2284 0 obj<>endobj +2285 0 obj<>endobj +2286 0 obj<>endobj +2287 0 obj<>endobj +2288 0 obj<>endobj +2289 0 obj<>endobj +2290 0 obj<>endobj +2291 0 obj<>endobj +2292 0 obj<>endobj +2293 0 obj<>endobj +2294 0 obj<>endobj +2295 0 obj<>endobj +2296 0 obj<>endobj +2297 0 obj<>endobj +2298 0 obj<>endobj +2299 0 obj<>endobj +2300 0 obj<>endobj +2301 0 obj<>endobj +2302 0 obj<>endobj +2303 0 obj<>endobj +2304 0 obj<>endobj +2305 0 obj<>endobj +2306 0 obj<>endobj +2307 0 obj<>endobj +2308 0 obj<>endobj +2309 0 obj<>endobj +2310 0 obj<>endobj +2311 0 obj<>endobj +2312 0 obj<>endobj +2313 0 obj<>endobj +2314 0 obj<>endobj +2315 0 obj<>endobj +2316 0 obj<>endobj +2317 0 obj<>endobj +2318 0 obj<>endobj +2319 0 obj<>endobj +2320 0 obj<>endobj +2321 0 obj<>endobj +2322 0 obj<>endobj +2323 0 obj<>endobj +2324 0 obj<>endobj +2325 0 obj<>endobj +2326 0 obj<>endobj +2327 0 obj<>endobj +2328 0 obj<>endobj +2329 0 obj<>endobj +2330 0 obj<>endobj +2331 0 obj<>endobj +2332 0 obj<>endobj +2333 0 obj<>endobj +2334 0 obj<>endobj +2335 0 obj<>endobj +2336 0 obj<>endobj +2337 0 obj<>endobj +2338 0 obj<>endobj +2339 0 obj<>endobj +2340 0 obj<>endobj +2341 0 obj<>endobj +2342 0 obj<>endobj +2343 0 obj<>endobj +2344 0 obj<>endobj +2345 0 obj<>endobj +2346 0 obj<>endobj +2347 0 obj<>endobj +2348 0 obj<>endobj +2349 0 obj<>endobj +2350 0 obj<>endobj +2351 0 obj<>endobj +2352 0 obj<>endobj +2353 0 obj<>endobj +2354 0 obj<>endobj +2355 0 obj<>endobj +2356 0 obj<>endobj +2357 0 obj<>endobj +2358 0 obj<>endobj +2359 0 obj<>endobj +2360 0 obj<>endobj +2361 0 obj<>endobj +2362 0 obj<>endobj +2363 0 obj<>endobj +2364 0 obj<>endobj +2365 0 obj<>endobj +2366 0 obj<>endobj +2367 0 obj<>endobj +2368 0 obj<>endobj +2369 0 obj<>endobj +2370 0 obj<>endobj +2371 0 obj<>endobj +2372 0 obj<>endobj +2373 0 obj<>endobj +2374 0 obj<>endobj +2375 0 obj<>endobj +2376 0 obj<>endobj +2377 0 obj<>endobj +2378 0 obj<>endobj +2379 0 obj<>endobj +2380 0 obj<>endobj +2381 0 obj<>endobj +2382 0 obj<>endobj +2383 0 obj<>endobj +2384 0 obj<>endobj +2385 0 obj<>endobj +2386 0 obj<>endobj +2387 0 obj<>endobj +2388 0 obj<>endobj +2389 0 obj<>endobj +2390 0 obj<>endobj +2391 0 obj<>endobj +2392 0 obj<>endobj +2393 0 obj<>endobj +2394 0 obj<>endobj +2395 0 obj<>endobj +2396 0 obj<>endobj +2397 0 obj<>endobj +2398 0 obj<>endobj +2399 0 obj<>endobj +2400 0 obj<>endobj +2401 0 obj<>endobj +2402 0 obj<>endobj +2403 0 obj<>endobj +2404 0 obj<>endobj +2405 0 obj<>endobj +2406 0 obj<>endobj +2407 0 obj<>endobj +2408 0 obj<>endobj +2409 0 obj<>endobj +2410 0 obj<>endobj +2411 0 obj<>endobj +2412 0 obj<>endobj +2413 0 obj<>endobj +2414 0 obj<>endobj +2415 0 obj<>endobj +2416 0 obj<>endobj +2417 0 obj<>endobj +2418 0 obj<>endobj +2419 0 obj<>endobj +2420 0 obj<>endobj +2421 0 obj<>endobj +2422 0 obj<>endobj +2423 0 obj<>endobj +2424 0 obj<>endobj +2425 0 obj<>endobj +2426 0 obj<>endobj +2427 0 obj<>endobj +2428 0 obj<>endobj +2429 0 obj<>endobj +2430 0 obj<>endobj +2431 0 obj<>endobj +2432 0 obj<>endobj +2433 0 obj<>endobj +2434 0 obj<>endobj +2435 0 obj<>endobj +2436 0 obj<>endobj +2437 0 obj<>endobj +2438 0 obj<>endobj +2439 0 obj<>endobj +2440 0 obj<>endobj +2441 0 obj<>endobj +2442 0 obj<>endobj +2443 0 obj<>endobj +2444 0 obj<>endobj +2445 0 obj<>endobj +2446 0 obj<>endobj +2447 0 obj<>endobj +2448 0 obj<>endobj +2449 0 obj<>endobj +2450 0 obj<>endobj +2451 0 obj<>endobj +2452 0 obj<>endobj +2453 0 obj<>endobj +2454 0 obj<>endobj +2455 0 obj<>endobj +2456 0 obj<>endobj +2457 0 obj<>endobj +2458 0 obj<>endobj +2459 0 obj<>endobj +2460 0 obj<>endobj +2461 0 obj<>endobj +2462 0 obj<>endobj +2463 0 obj<>endobj +2464 0 obj<>endobj +2465 0 obj<>endobj +2466 0 obj<>endobj +2467 0 obj<>endobj +2468 0 obj<>endobj +2469 0 obj<>endobj +2470 0 obj<>endobj +2471 0 obj<>endobj +2472 0 obj<>endobj +2473 0 obj<>endobj +2474 0 obj<>endobj +2475 0 obj<>endobj +2476 0 obj<>endobj +2477 0 obj<>endobj +2478 0 obj<>endobj +2479 0 obj<>endobj +2480 0 obj<>endobj +2481 0 obj<>endobj +2482 0 obj<>endobj +2483 0 obj<>endobj +2484 0 obj<>endobj +2485 0 obj<>endobj +2486 0 obj<>endobj +2487 0 obj<>endobj +2488 0 obj<>endobj +2489 0 obj<>endobj +2490 0 obj<>endobj +2491 0 obj<>endobj +2492 0 obj<>endobj +2493 0 obj<>endobj +2494 0 obj<>endobj +2495 0 obj<>endobj +2496 0 obj<>endobj +2497 0 obj<>endobj +2498 0 obj<>endobj +2499 0 obj<>endobj +2500 0 obj<>endobj +2501 0 obj<>endobj +2502 0 obj<>endobj +2503 0 obj<>endobj +2504 0 obj<>endobj +2505 0 obj<>endobj +2506 0 obj<>endobj +2507 0 obj<>endobj +2508 0 obj<>endobj +2509 0 obj<>endobj +2510 0 obj<>endobj +2511 0 obj<>endobj +2512 0 obj<>endobj +2513 0 obj<>endobj +2514 0 obj<>endobj +2515 0 obj<>endobj +2516 0 obj<>endobj +2517 0 obj<>endobj +2518 0 obj<>endobj +2519 0 obj<>endobj +2520 0 obj<>endobj +2521 0 obj<>endobj +2522 0 obj<>endobj +2523 0 obj<>endobj +2524 0 obj<>endobj +2525 0 obj<>endobj +2526 0 obj<>endobj +2527 0 obj<>endobj +2528 0 obj<>endobj +2529 0 obj<>endobj +2530 0 obj<>endobj +2531 0 obj<>endobj +2532 0 obj<>endobj +2533 0 obj<>endobj +2534 0 obj<>endobj +2535 0 obj<>endobj +2536 0 obj<>endobj +2537 0 obj<>endobj +2538 0 obj<>endobj +2539 0 obj<>endobj +2540 0 obj<>endobj +2541 0 obj<>endobj +2542 0 obj<>endobj +2543 0 obj<>endobj +2544 0 obj<>endobj +2545 0 obj<>endobj +2546 0 obj<>endobj +2547 0 obj<>endobj +2548 0 obj<>endobj +2549 0 obj<>endobj +2550 0 obj<>endobj +2551 0 obj<>endobj +2552 0 obj<>endobj +2553 0 obj<>endobj +2554 0 obj<>endobj +2555 0 obj<>endobj +2556 0 obj<>endobj +2557 0 obj<>endobj +2558 0 obj<>endobj +2559 0 obj<>endobj +2560 0 obj<>endobj +2561 0 obj<>endobj +2562 0 obj<>endobj +2563 0 obj<>endobj +2564 0 obj<>endobj +2565 0 obj<>endobj +2566 0 obj<>endobj +2567 0 obj<>endobj +2568 0 obj<>endobj +2569 0 obj<>endobj +2570 0 obj<>endobj +2571 0 obj<>endobj +2572 0 obj<>endobj +2573 0 obj<>endobj +2574 0 obj<>endobj +2575 0 obj<>endobj +2576 0 obj<>endobj +2577 0 obj<>endobj +2578 0 obj<>endobj +2579 0 obj<>endobj +2580 0 obj<>endobj +2581 0 obj<>endobj +2582 0 obj<>endobj +2583 0 obj<>endobj +2584 0 obj<>endobj +2585 0 obj<>endobj +2586 0 obj<>endobj +2587 0 obj<>endobj +2588 0 obj<>endobj +2589 0 obj<>endobj +2590 0 obj<>endobj +2591 0 obj<>endobj +2592 0 obj<>endobj +2593 0 obj<>endobj +2594 0 obj<>endobj +2595 0 obj<>endobj +2596 0 obj<>endobj +2597 0 obj<>endobj +2598 0 obj<>endobj +2599 0 obj<>endobj +2600 0 obj<>endobj +2601 0 obj<>endobj +2602 0 obj<>endobj +2603 0 obj<>endobj +2604 0 obj<>endobj +2605 0 obj<>endobj +2606 0 obj<>endobj +2607 0 obj<>endobj +2608 0 obj<>endobj +2609 0 obj<>endobj +2610 0 obj<>endobj +2611 0 obj<>endobj +2612 0 obj<>endobj +2613 0 obj<>endobj +2614 0 obj<>endobj +2615 0 obj<>endobj +2616 0 obj<>endobj +2617 0 obj<>endobj +2618 0 obj<>endobj +2619 0 obj<>endobj +2620 0 obj<>endobj +2621 0 obj<>endobj +2622 0 obj<>endobj +2623 0 obj<>endobj +2624 0 obj<>endobj +2625 0 obj<>endobj +2626 0 obj<>endobj +2627 0 obj<>endobj +2628 0 obj<>endobj +2629 0 obj<>endobj +2630 0 obj<>endobj +2631 0 obj<>endobj +2632 0 obj<>endobj +2633 0 obj<>endobj +2634 0 obj<>endobj +2635 0 obj<>endobj +2636 0 obj<>endobj +2637 0 obj<>endobj +2638 0 obj<>endobj +2639 0 obj<>endobj +2640 0 obj<>endobj +2641 0 obj<>endobj +2642 0 obj<>endobj +2643 0 obj<>endobj +2644 0 obj<>endobj +2645 0 obj<>endobj +2646 0 obj<>endobj +2647 0 obj<>endobj +2648 0 obj<>endobj +2649 0 obj<>endobj +2650 0 obj<>endobj +2651 0 obj<>endobj +2652 0 obj<>endobj +2653 0 obj<>endobj +2654 0 obj<>endobj +2655 0 obj<>endobj +2656 0 obj<>endobj +2657 0 obj<>endobj +2658 0 obj<>endobj +2659 0 obj<>endobj +2660 0 obj<>endobj +2661 0 obj<>endobj +2662 0 obj<>endobj +2663 0 obj<>endobj +2664 0 obj<>endobj +2665 0 obj<>endobj +2666 0 obj<>endobj +2667 0 obj<>endobj +2668 0 obj<>endobj +2669 0 obj<>endobj +2670 0 obj<>endobj +2671 0 obj<>endobj +2672 0 obj<>endobj +2673 0 obj<>endobj +2674 0 obj<>endobj +2675 0 obj<>endobj +2676 0 obj<>endobj +2677 0 obj<>endobj +2678 0 obj<>endobj +2679 0 obj<>endobj +2680 0 obj<>endobj +2681 0 obj<>endobj +2682 0 obj<>endobj +2683 0 obj<>endobj +2684 0 obj<>endobj +2685 0 obj<>endobj +2686 0 obj<>endobj +2687 0 obj<>endobj +2688 0 obj<>endobj +2689 0 obj<>endobj +2690 0 obj<>endobj +2691 0 obj<>endobj +2692 0 obj<>endobj +2693 0 obj<>endobj +2694 0 obj<>endobj +2695 0 obj<>endobj +2696 0 obj<>endobj +2697 0 obj<>endobj +2698 0 obj<>endobj +2699 0 obj<>endobj +2700 0 obj<>endobj +2701 0 obj<>endobj +2702 0 obj<>endobj +2703 0 obj<>endobj +2704 0 obj<>endobj +2705 0 obj<>endobj +2706 0 obj<>endobj +2707 0 obj<>endobj +2708 0 obj<>endobj +2709 0 obj<>endobj +2710 0 obj<>endobj +2711 0 obj<>endobj +2712 0 obj<>endobj +2713 0 obj<>endobj +2714 0 obj<>endobj +2715 0 obj<>endobj +2716 0 obj<>endobj +2717 0 obj<>endobj +2718 0 obj<>endobj +2719 0 obj<>endobj +2720 0 obj<>endobj +2721 0 obj<>endobj +2722 0 obj<>endobj +2723 0 obj<>endobj +2724 0 obj<>endobj +2725 0 obj<>endobj +2726 0 obj<>endobj +2727 0 obj<>endobj +2728 0 obj<>endobj +2729 0 obj<>endobj +2730 0 obj<>endobj +2731 0 obj<>endobj +2732 0 obj<>endobj +2733 0 obj<>endobj +2734 0 obj<>endobj +2735 0 obj<>endobj +2736 0 obj<>endobj +2737 0 obj<>endobj +2738 0 obj<>endobj +2739 0 obj<>endobj +2740 0 obj<>endobj +2741 0 obj<>endobj +2742 0 obj<>endobj +2743 0 obj<>endobj +2744 0 obj<>endobj +2745 0 obj<>endobj +2746 0 obj<>endobj +2747 0 obj<>endobj +2748 0 obj<>endobj +2749 0 obj<>endobj +2750 0 obj<>endobj +2751 0 obj<>endobj +2752 0 obj<>endobj +2753 0 obj<>endobj +2754 0 obj<>endobj +2755 0 obj<>endobj +2756 0 obj<>endobj +2757 0 obj<>endobj +2758 0 obj<>endobj +2759 0 obj<>endobj +2760 0 obj<>endobj +2761 0 obj<>endobj +2762 0 obj<>endobj +2763 0 obj<>endobj +2764 0 obj<>endobj +2765 0 obj<>endobj +2766 0 obj<>endobj +2767 0 obj<>endobj +2768 0 obj<>endobj +2769 0 obj<>endobj +2770 0 obj<>endobj +2771 0 obj<>endobj +2772 0 obj<>endobj +2773 0 obj<>endobj +2774 0 obj<>endobj +2775 0 obj<>endobj +2776 0 obj<>endobj +2777 0 obj<>endobj +2778 0 obj<>endobj +2779 0 obj<>endobj +2780 0 obj<>endobj +2781 0 obj<>endobj +2782 0 obj<>endobj +2783 0 obj<>endobj +2784 0 obj<>endobj +2785 0 obj<>endobj +2786 0 obj<>endobj +2787 0 obj<>endobj +2788 0 obj<>endobj +2789 0 obj<>endobj +2790 0 obj<>endobj +2791 0 obj<>endobj +2792 0 obj<>endobj +2793 0 obj<>endobj +2794 0 obj<>endobj +2795 0 obj<>endobj +2796 0 obj<>endobj +2797 0 obj<>endobj +2798 0 obj<>endobj +2799 0 obj<>endobj +2800 0 obj<>endobj +2801 0 obj<>endobj +2802 0 obj<>endobj +2803 0 obj<>endobj +2804 0 obj<>endobj +2805 0 obj<>endobj +2806 0 obj<>endobj +2807 0 obj<>endobj +2808 0 obj<>endobj +2809 0 obj<>endobj +2810 0 obj<>endobj +2811 0 obj<>endobj +2812 0 obj<>endobj +2813 0 obj<>endobj +2814 0 obj<>endobj +2815 0 obj<>endobj +2816 0 obj<>endobj +2817 0 obj<>endobj +2818 0 obj<>endobj +2819 0 obj<>endobj +2820 0 obj<>endobj +2821 0 obj<>endobj +2822 0 obj<>endobj +2823 0 obj<>endobj +2824 0 obj<>endobj +2825 0 obj<>endobj +2826 0 obj<>endobj +2827 0 obj<>endobj +2828 0 obj<>endobj +2829 0 obj<>endobj +2830 0 obj<>endobj +2831 0 obj<>endobj +2832 0 obj<>endobj +2833 0 obj<>endobj +2834 0 obj<>endobj +2835 0 obj<>endobj +2836 0 obj<>endobj +2837 0 obj<>endobj +2838 0 obj<>endobj +2839 0 obj<>endobj +2840 0 obj<>endobj +2841 0 obj<>endobj +2842 0 obj<>endobj +2843 0 obj<>endobj +2844 0 obj<>endobj +2845 0 obj<>endobj +2846 0 obj<>endobj +2847 0 obj<>endobj +2848 0 obj<>endobj +2849 0 obj<>endobj +2850 0 obj<>endobj +2851 0 obj<>endobj +2852 0 obj<>endobj +2853 0 obj<>endobj +2854 0 obj<>endobj +2855 0 obj<>endobj +2856 0 obj<>endobj +2857 0 obj<>endobj +2858 0 obj<>endobj +2859 0 obj<>endobj +2860 0 obj<>endobj +2861 0 obj<>endobj +2862 0 obj<>endobj +2863 0 obj<>endobj +2864 0 obj<>endobj +2865 0 obj<>endobj +2866 0 obj<>endobj +2867 0 obj<>endobj +2868 0 obj<>endobj +2869 0 obj<>endobj +2870 0 obj<>endobj +2871 0 obj<>endobj +2872 0 obj<>1<>2<>20<>]>>>>endobj +xref +0 2873 +0000000000 65535 f +0000000015 00000 n +0000000233 00000 n +0000001799 00000 n +0000001873 00000 n +0000001951 00000 n +0000002028 00000 n +0000002107 00000 n +0000002183 00000 n +0000002264 00000 n +0000002348 00000 n +0000002407 00000 n +0000002459 00000 n +0000002544 00000 n +0000002568 00000 n +0000002673 00000 n +0000002779 00000 n +0000002885 00000 n +0000002923 00000 n +0000003029 00000 n +0000003134 00000 n +0000003240 00000 n +0000003278 00000 n +0000003383 00000 n +0000003489 00000 n +0000003593 00000 n +0000003631 00000 n +0000003736 00000 n +0000003842 00000 n +0000003948 00000 n +0000004053 00000 n +0000004159 00000 n +0000004265 00000 n +0000004371 00000 n +0000004476 00000 n +0000004582 00000 n +0000004662 00000 n +0000004767 00000 n +0000004873 00000 n +0000004979 00000 n +0000005082 00000 n +0000005127 00000 n +0000005233 00000 n +0000005338 00000 n +0000005444 00000 n +0000005550 00000 n +0000005656 00000 n +0000005761 00000 n +0000005867 00000 n +0000005933 00000 n +0000006038 00000 n +0000006144 00000 n +0000006250 00000 n +0000006356 00000 n +0000006401 00000 n +0000006504 00000 n +0000006608 00000 n +0000006639 00000 n +0000006744 00000 n +0000006850 00000 n +0000006881 00000 n +0000006986 00000 n +0000007092 00000 n +0000007198 00000 n +0000007304 00000 n +0000007349 00000 n +0000007454 00000 n +0000007478 00000 n +0000007581 00000 n +0000007685 00000 n +0000007716 00000 n +0000007821 00000 n +0000007927 00000 n +0000008033 00000 n +0000008139 00000 n +0000008245 00000 n +0000008297 00000 n +0000008402 00000 n +0000008508 00000 n +0000008614 00000 n +0000008720 00000 n +0000008826 00000 n +0000008878 00000 n +0000008983 00000 n +0000009089 00000 n +0000009195 00000 n +0000009301 00000 n +0000009407 00000 n +0000009459 00000 n +0000009564 00000 n +0000009670 00000 n +0000009776 00000 n +0000009882 00000 n +0000009988 00000 n +0000010040 00000 n +0000010145 00000 n +0000010251 00000 n +0000010357 00000 n +0000010463 00000 n +0000010569 00000 n +0000010621 00000 n +0000010727 00000 n +0000010834 00000 n +0000010941 00000 n +0000011048 00000 n +0000011155 00000 n +0000011213 00000 n +0000011319 00000 n +0000011426 00000 n +0000011460 00000 n +0000011566 00000 n +0000011673 00000 n +0000011780 00000 n +0000011887 00000 n +0000011937 00000 n +0000012043 00000 n +0000012150 00000 n +0000012257 00000 n +0000012364 00000 n +0000012414 00000 n +0000012520 00000 n +0000012627 00000 n +0000012661 00000 n +0000012767 00000 n +0000012874 00000 n +0000012981 00000 n +0000013088 00000 n +0000013194 00000 n +0000013252 00000 n +0000013358 00000 n +0000013465 00000 n +0000013572 00000 n +0000013679 00000 n +0000013785 00000 n +0000013843 00000 n +0000013949 00000 n +0000014056 00000 n +0000014163 00000 n +0000014270 00000 n +0000014376 00000 n +0000014434 00000 n +0000014540 00000 n +0000014647 00000 n +0000014754 00000 n +0000014861 00000 n +0000014967 00000 n +0000015025 00000 n +0000015131 00000 n +0000015238 00000 n +0000015345 00000 n +0000015452 00000 n +0000015557 00000 n +0000015615 00000 n +0000015721 00000 n +0000015828 00000 n +0000015935 00000 n +0000016042 00000 n +0000016148 00000 n +0000016206 00000 n +0000016312 00000 n +0000016419 00000 n +0000016453 00000 n +0000016559 00000 n +0000016666 00000 n +0000016700 00000 n +0000016806 00000 n +0000016913 00000 n +0000017020 00000 n +0000017126 00000 n +0000017233 00000 n +0000017340 00000 n +0000017447 00000 n +0000017554 00000 n +0000017661 00000 n +0000017768 00000 n +0000017875 00000 n +0000017981 00000 n +0000018088 00000 n +0000018195 00000 n +0000018302 00000 n +0000018409 00000 n +0000018516 00000 n +0000018623 00000 n +0000018730 00000 n +0000018837 00000 n +0000018944 00000 n +0000019051 00000 n +0000019158 00000 n +0000019265 00000 n +0000019372 00000 n +0000019479 00000 n +0000019586 00000 n +0000019693 00000 n +0000019800 00000 n +0000019907 00000 n +0000020014 00000 n +0000020121 00000 n +0000020228 00000 n +0000020335 00000 n +0000020442 00000 n +0000020549 00000 n +0000020656 00000 n +0000020763 00000 n +0000020870 00000 n +0000020977 00000 n +0000021084 00000 n +0000021191 00000 n +0000021297 00000 n +0000021402 00000 n +0000021507 00000 n +0000021885 00000 n +0000021992 00000 n +0000022099 00000 n +0000022206 00000 n +0000022313 00000 n +0000022420 00000 n +0000022527 00000 n +0000022634 00000 n +0000022741 00000 n +0000022847 00000 n +0000022953 00000 n +0000023060 00000 n +0000023167 00000 n +0000023274 00000 n +0000023380 00000 n +0000023487 00000 n +0000023593 00000 n +0000023699 00000 n +0000023805 00000 n +0000023911 00000 n +0000024018 00000 n +0000024125 00000 n +0000024231 00000 n +0000024338 00000 n +0000024445 00000 n +0000024552 00000 n +0000024659 00000 n +0000024765 00000 n +0000024871 00000 n +0000024977 00000 n +0000025084 00000 n +0000025191 00000 n +0000025298 00000 n +0000025405 00000 n +0000025511 00000 n +0000025618 00000 n +0000025724 00000 n +0000025830 00000 n +0000025936 00000 n +0000026042 00000 n +0000026148 00000 n +0000026253 00000 n +0000026357 00000 n +0000026461 00000 n +0000026823 00000 n +0000026930 00000 n +0000027036 00000 n +0000027142 00000 n +0000027249 00000 n +0000027356 00000 n +0000027463 00000 n +0000027570 00000 n +0000027677 00000 n +0000027784 00000 n +0000027891 00000 n +0000027998 00000 n +0000028105 00000 n +0000028212 00000 n +0000028319 00000 n +0000028426 00000 n +0000028533 00000 n +0000028640 00000 n +0000028747 00000 n +0000028854 00000 n +0000028961 00000 n +0000029068 00000 n +0000029175 00000 n +0000029282 00000 n +0000029389 00000 n +0000029496 00000 n +0000029603 00000 n +0000029710 00000 n +0000029817 00000 n +0000029924 00000 n +0000030031 00000 n +0000030138 00000 n +0000030245 00000 n +0000030352 00000 n +0000030459 00000 n +0000030566 00000 n +0000030673 00000 n +0000030780 00000 n +0000030887 00000 n +0000030994 00000 n +0000031101 00000 n +0000031208 00000 n +0000031315 00000 n +0000031421 00000 n +0000031526 00000 n +0000031631 00000 n +0000032009 00000 n +0000032116 00000 n +0000032223 00000 n +0000032330 00000 n +0000032437 00000 n +0000032544 00000 n +0000032650 00000 n +0000032757 00000 n +0000032864 00000 n +0000032971 00000 n +0000033078 00000 n +0000033185 00000 n +0000033291 00000 n +0000033398 00000 n +0000033505 00000 n +0000033612 00000 n +0000033719 00000 n +0000033826 00000 n +0000033933 00000 n +0000034039 00000 n +0000034146 00000 n +0000034253 00000 n +0000034360 00000 n +0000034467 00000 n +0000034574 00000 n +0000034680 00000 n +0000034787 00000 n +0000034894 00000 n +0000035001 00000 n +0000035108 00000 n +0000035215 00000 n +0000035322 00000 n +0000035428 00000 n +0000035535 00000 n +0000035642 00000 n +0000035749 00000 n +0000035856 00000 n +0000035963 00000 n +0000036069 00000 n +0000036176 00000 n +0000036283 00000 n +0000036390 00000 n +0000036497 00000 n +0000036604 00000 n +0000036711 00000 n +0000036816 00000 n +0000036921 00000 n +0000037026 00000 n +0000037420 00000 n +0000037527 00000 n +0000037634 00000 n +0000037741 00000 n +0000037848 00000 n +0000037955 00000 n +0000038062 00000 n +0000038169 00000 n +0000038276 00000 n +0000038383 00000 n +0000038490 00000 n +0000038597 00000 n +0000038704 00000 n +0000038811 00000 n +0000038918 00000 n +0000039025 00000 n +0000039132 00000 n +0000039239 00000 n +0000039346 00000 n +0000039453 00000 n +0000039560 00000 n +0000039667 00000 n +0000039774 00000 n +0000039881 00000 n +0000039988 00000 n +0000040095 00000 n +0000040202 00000 n +0000040309 00000 n +0000040416 00000 n +0000040523 00000 n +0000040630 00000 n +0000040737 00000 n +0000040844 00000 n +0000040951 00000 n +0000041058 00000 n +0000041165 00000 n +0000041272 00000 n +0000041379 00000 n +0000041486 00000 n +0000041593 00000 n +0000041700 00000 n +0000041807 00000 n +0000041914 00000 n +0000042021 00000 n +0000042128 00000 n +0000042234 00000 n +0000042339 00000 n +0000042444 00000 n +0000042838 00000 n +0000042945 00000 n +0000043052 00000 n +0000043158 00000 n +0000043265 00000 n +0000043372 00000 n +0000043479 00000 n +0000043586 00000 n +0000043693 00000 n +0000043799 00000 n +0000043906 00000 n +0000044013 00000 n +0000044120 00000 n +0000044227 00000 n +0000044334 00000 n +0000044441 00000 n +0000044547 00000 n +0000044654 00000 n +0000044761 00000 n +0000044868 00000 n +0000044975 00000 n +0000045082 00000 n +0000045189 00000 n +0000045295 00000 n +0000045402 00000 n +0000045509 00000 n +0000045616 00000 n +0000045723 00000 n +0000045830 00000 n +0000045937 00000 n +0000046043 00000 n +0000046150 00000 n +0000046257 00000 n +0000046364 00000 n +0000046471 00000 n +0000046578 00000 n +0000046685 00000 n +0000046791 00000 n +0000046898 00000 n +0000047005 00000 n +0000047112 00000 n +0000047219 00000 n +0000047326 00000 n +0000047433 00000 n +0000047539 00000 n +0000047645 00000 n +0000047750 00000 n +0000047855 00000 n +0000048249 00000 n +0000048356 00000 n +0000048463 00000 n +0000048570 00000 n +0000048677 00000 n +0000048784 00000 n +0000048891 00000 n +0000048998 00000 n +0000049105 00000 n +0000049212 00000 n +0000049319 00000 n +0000049426 00000 n +0000049533 00000 n +0000049640 00000 n +0000049747 00000 n +0000049854 00000 n +0000049961 00000 n +0000050068 00000 n +0000050175 00000 n +0000050282 00000 n +0000050389 00000 n +0000050496 00000 n +0000050603 00000 n +0000050710 00000 n +0000050817 00000 n +0000050924 00000 n +0000051031 00000 n +0000051138 00000 n +0000051245 00000 n +0000051352 00000 n +0000051459 00000 n +0000051566 00000 n +0000051673 00000 n +0000051780 00000 n +0000051887 00000 n +0000051994 00000 n +0000052101 00000 n +0000052208 00000 n +0000052315 00000 n +0000052422 00000 n +0000052529 00000 n +0000052636 00000 n +0000052743 00000 n +0000052850 00000 n +0000052957 00000 n +0000053063 00000 n +0000053168 00000 n +0000053273 00000 n +0000053667 00000 n +0000053774 00000 n +0000053881 00000 n +0000053987 00000 n +0000054094 00000 n +0000054201 00000 n +0000054308 00000 n +0000054415 00000 n +0000054522 00000 n +0000054629 00000 n +0000054735 00000 n +0000054842 00000 n +0000054949 00000 n +0000055056 00000 n +0000055163 00000 n +0000055270 00000 n +0000055377 00000 n +0000055483 00000 n +0000055590 00000 n +0000055697 00000 n +0000055804 00000 n +0000055911 00000 n +0000056018 00000 n +0000056125 00000 n +0000056231 00000 n +0000056338 00000 n +0000056445 00000 n +0000056552 00000 n +0000056659 00000 n +0000056766 00000 n +0000056873 00000 n +0000056979 00000 n +0000057086 00000 n +0000057193 00000 n +0000057300 00000 n +0000057407 00000 n +0000057514 00000 n +0000057621 00000 n +0000057727 00000 n +0000057834 00000 n +0000057941 00000 n +0000058048 00000 n +0000058155 00000 n +0000058262 00000 n +0000058369 00000 n +0000058474 00000 n +0000058579 00000 n +0000058684 00000 n +0000059078 00000 n +0000059185 00000 n +0000059292 00000 n +0000059399 00000 n +0000059506 00000 n +0000059613 00000 n +0000059720 00000 n +0000059827 00000 n +0000059934 00000 n +0000060041 00000 n +0000060148 00000 n +0000060255 00000 n +0000060362 00000 n +0000060469 00000 n +0000060576 00000 n +0000060683 00000 n +0000060790 00000 n +0000060897 00000 n +0000061004 00000 n +0000061111 00000 n +0000061218 00000 n +0000061325 00000 n +0000061432 00000 n +0000061539 00000 n +0000061646 00000 n +0000061753 00000 n +0000061860 00000 n +0000061967 00000 n +0000062074 00000 n +0000062181 00000 n +0000062288 00000 n +0000062395 00000 n +0000062502 00000 n +0000062609 00000 n +0000062716 00000 n +0000062823 00000 n +0000062930 00000 n +0000063037 00000 n +0000063144 00000 n +0000063251 00000 n +0000063358 00000 n +0000063465 00000 n +0000063572 00000 n +0000063679 00000 n +0000063786 00000 n +0000063892 00000 n +0000063997 00000 n +0000064102 00000 n +0000064496 00000 n +0000064603 00000 n +0000064710 00000 n +0000064817 00000 n +0000064924 00000 n +0000065031 00000 n +0000065138 00000 n +0000065244 00000 n +0000065351 00000 n +0000065458 00000 n +0000065565 00000 n +0000065672 00000 n +0000065779 00000 n +0000065886 00000 n +0000065992 00000 n +0000066099 00000 n +0000066206 00000 n +0000066313 00000 n +0000066420 00000 n +0000066527 00000 n +0000066634 00000 n +0000066740 00000 n +0000066847 00000 n +0000066954 00000 n +0000067061 00000 n +0000067168 00000 n +0000067275 00000 n +0000067382 00000 n +0000067488 00000 n +0000067595 00000 n +0000067702 00000 n +0000067809 00000 n +0000067916 00000 n +0000068023 00000 n +0000068130 00000 n +0000068236 00000 n +0000068343 00000 n +0000068450 00000 n +0000068557 00000 n +0000068664 00000 n +0000068771 00000 n +0000068878 00000 n +0000068984 00000 n +0000069091 00000 n +0000069198 00000 n +0000069304 00000 n +0000069409 00000 n +0000069514 00000 n +0000069908 00000 n +0000070015 00000 n +0000070122 00000 n +0000070229 00000 n +0000070336 00000 n +0000070443 00000 n +0000070550 00000 n +0000070657 00000 n +0000070764 00000 n +0000070871 00000 n +0000070978 00000 n +0000071085 00000 n +0000071192 00000 n +0000071299 00000 n +0000071406 00000 n +0000071513 00000 n +0000071620 00000 n +0000071727 00000 n +0000071834 00000 n +0000071941 00000 n +0000072048 00000 n +0000072155 00000 n +0000072262 00000 n +0000072369 00000 n +0000072476 00000 n +0000072583 00000 n +0000072690 00000 n +0000072797 00000 n +0000072904 00000 n +0000073011 00000 n +0000073118 00000 n +0000073225 00000 n +0000073332 00000 n +0000073439 00000 n +0000073546 00000 n +0000073653 00000 n +0000073760 00000 n +0000073867 00000 n +0000073974 00000 n +0000074081 00000 n +0000074188 00000 n +0000074295 00000 n +0000074402 00000 n +0000074509 00000 n +0000074616 00000 n +0000074722 00000 n +0000074827 00000 n +0000074932 00000 n +0000075326 00000 n +0000075433 00000 n +0000075540 00000 n +0000075647 00000 n +0000075753 00000 n +0000075860 00000 n +0000075967 00000 n +0000076074 00000 n +0000076181 00000 n +0000076288 00000 n +0000076395 00000 n +0000076501 00000 n +0000076608 00000 n +0000076715 00000 n +0000076822 00000 n +0000076929 00000 n +0000077036 00000 n +0000077143 00000 n +0000077249 00000 n +0000077356 00000 n +0000077463 00000 n +0000077570 00000 n +0000077677 00000 n +0000077784 00000 n +0000077891 00000 n +0000077997 00000 n +0000078104 00000 n +0000078211 00000 n +0000078318 00000 n +0000078425 00000 n +0000078532 00000 n +0000078639 00000 n +0000078745 00000 n +0000078852 00000 n +0000078959 00000 n +0000079066 00000 n +0000079173 00000 n +0000079280 00000 n +0000079387 00000 n +0000079493 00000 n +0000079600 00000 n +0000079707 00000 n +0000079814 00000 n +0000079921 00000 n +0000080028 00000 n +0000080134 00000 n +0000080238 00000 n +0000080343 00000 n +0000080737 00000 n +0000080844 00000 n +0000080951 00000 n +0000081058 00000 n +0000081165 00000 n +0000081272 00000 n +0000081379 00000 n +0000081486 00000 n +0000081593 00000 n +0000081700 00000 n +0000081807 00000 n +0000081914 00000 n +0000082021 00000 n +0000082128 00000 n +0000082235 00000 n +0000082342 00000 n +0000082449 00000 n +0000082556 00000 n +0000082663 00000 n +0000082770 00000 n +0000082877 00000 n +0000082984 00000 n +0000083091 00000 n +0000083198 00000 n +0000083305 00000 n +0000083412 00000 n +0000083519 00000 n +0000083626 00000 n +0000083733 00000 n +0000083840 00000 n +0000083947 00000 n +0000084054 00000 n +0000084161 00000 n +0000084268 00000 n +0000084375 00000 n +0000084482 00000 n +0000084589 00000 n +0000084696 00000 n +0000084803 00000 n +0000084910 00000 n +0000085017 00000 n +0000085124 00000 n +0000085231 00000 n +0000085338 00000 n +0000085445 00000 n +0000085551 00000 n +0000085656 00000 n +0000085761 00000 n +0000086155 00000 n +0000086261 00000 n +0000086368 00000 n +0000086475 00000 n +0000086582 00000 n +0000086689 00000 n +0000086796 00000 n +0000086903 00000 n +0000087009 00000 n +0000087116 00000 n +0000087223 00000 n +0000087330 00000 n +0000087437 00000 n +0000087544 00000 n +0000087651 00000 n +0000087757 00000 n +0000087864 00000 n +0000087971 00000 n +0000088078 00000 n +0000088185 00000 n +0000088292 00000 n +0000088399 00000 n +0000088505 00000 n +0000088612 00000 n +0000088719 00000 n +0000088826 00000 n +0000088933 00000 n +0000089040 00000 n +0000089147 00000 n +0000089253 00000 n +0000089360 00000 n +0000089467 00000 n +0000089574 00000 n +0000089681 00000 n +0000089788 00000 n +0000089895 00000 n +0000090001 00000 n +0000090108 00000 n +0000090215 00000 n +0000090322 00000 n +0000090429 00000 n +0000090536 00000 n +0000090643 00000 n +0000090749 00000 n +0000090856 00000 n +0000090962 00000 n +0000091067 00000 n +0000091172 00000 n +0000091566 00000 n +0000091673 00000 n +0000091780 00000 n +0000091887 00000 n +0000091994 00000 n +0000092101 00000 n +0000092208 00000 n +0000092315 00000 n +0000092422 00000 n +0000092529 00000 n +0000092636 00000 n +0000092743 00000 n +0000092850 00000 n +0000092957 00000 n +0000093064 00000 n +0000093171 00000 n +0000093278 00000 n +0000093385 00000 n +0000093492 00000 n +0000093599 00000 n +0000093706 00000 n +0000093813 00000 n +0000093920 00000 n +0000094027 00000 n +0000094134 00000 n +0000094241 00000 n +0000094348 00000 n +0000094455 00000 n +0000094562 00000 n +0000094669 00000 n +0000094776 00000 n +0000094883 00000 n +0000094990 00000 n +0000095097 00000 n +0000095204 00000 n +0000095311 00000 n +0000095418 00000 n +0000095525 00000 n +0000095632 00000 n +0000095739 00000 n +0000095846 00000 n +0000095953 00000 n +0000096060 00000 n +0000096167 00000 n +0000096274 00000 n +0000096380 00000 n +0000096485 00000 n +0000096590 00000 n +0000096984 00000 n +0000097091 00000 n +0000097198 00000 n +0000097305 00000 n +0000097412 00000 n +0000097518 00000 n +0000097625 00000 n +0000097732 00000 n +0000097839 00000 n +0000097946 00000 n +0000098053 00000 n +0000098160 00000 n +0000098266 00000 n +0000098373 00000 n +0000098480 00000 n +0000098587 00000 n +0000098694 00000 n +0000098801 00000 n +0000098908 00000 n +0000099014 00000 n +0000099121 00000 n +0000099228 00000 n +0000099335 00000 n +0000099442 00000 n +0000099549 00000 n +0000099656 00000 n +0000099762 00000 n +0000099869 00000 n +0000099976 00000 n +0000100083 00000 n +0000100190 00000 n +0000100297 00000 n +0000100404 00000 n +0000100510 00000 n +0000100617 00000 n +0000100724 00000 n +0000100831 00000 n +0000100938 00000 n +0000101045 00000 n +0000101152 00000 n +0000101258 00000 n +0000101365 00000 n +0000101472 00000 n +0000101579 00000 n +0000101686 00000 n +0000101792 00000 n +0000101897 00000 n +0000102001 00000 n +0000102395 00000 n +0000102502 00000 n +0000102609 00000 n +0000102716 00000 n +0000102823 00000 n +0000102930 00000 n +0000103037 00000 n +0000103103 00000 n +0000103137 00000 n +0000103171 00000 n +0000115544 00000 n +0000115594 00000 n +0000115644 00000 n +0000115694 00000 n +0000115744 00000 n +0000115794 00000 n +0000115844 00000 n +0000115894 00000 n +0000115944 00000 n +0000115994 00000 n +0000116044 00000 n +0000116094 00000 n +0000116144 00000 n +0000116194 00000 n +0000116244 00000 n +0000116294 00000 n +0000116344 00000 n +0000116394 00000 n +0000116444 00000 n +0000116494 00000 n +0000116544 00000 n +0000116594 00000 n +0000116644 00000 n +0000116694 00000 n +0000116744 00000 n +0000116794 00000 n +0000116844 00000 n +0000116894 00000 n +0000116944 00000 n +0000116994 00000 n +0000117044 00000 n +0000117094 00000 n +0000117144 00000 n +0000117194 00000 n +0000117244 00000 n +0000117294 00000 n +0000117344 00000 n +0000117394 00000 n +0000117444 00000 n +0000117494 00000 n +0000117544 00000 n +0000117594 00000 n +0000117644 00000 n +0000117694 00000 n +0000117744 00000 n +0000117794 00000 n +0000117844 00000 n +0000117894 00000 n +0000117944 00000 n +0000117994 00000 n +0000118044 00000 n +0000118094 00000 n +0000118144 00000 n +0000118194 00000 n +0000118244 00000 n +0000118294 00000 n +0000118344 00000 n +0000118394 00000 n +0000118444 00000 n +0000118494 00000 n +0000118544 00000 n +0000118594 00000 n +0000118644 00000 n +0000118694 00000 n +0000118744 00000 n +0000118794 00000 n +0000118844 00000 n +0000118895 00000 n +0000118946 00000 n +0000118997 00000 n +0000119048 00000 n +0000119099 00000 n +0000119150 00000 n +0000119201 00000 n +0000119252 00000 n +0000119303 00000 n +0000119354 00000 n +0000119405 00000 n +0000119456 00000 n +0000119507 00000 n +0000119558 00000 n +0000119609 00000 n +0000119660 00000 n +0000119711 00000 n +0000119762 00000 n +0000119813 00000 n +0000119864 00000 n +0000119915 00000 n +0000119966 00000 n +0000120017 00000 n +0000120068 00000 n +0000120119 00000 n +0000120170 00000 n +0000120221 00000 n +0000120272 00000 n +0000120323 00000 n +0000120374 00000 n +0000120425 00000 n +0000120476 00000 n +0000120527 00000 n +0000120578 00000 n +0000120629 00000 n +0000120680 00000 n +0000120731 00000 n +0000120782 00000 n +0000120833 00000 n +0000120884 00000 n +0000120935 00000 n +0000120986 00000 n +0000121037 00000 n +0000121088 00000 n +0000121139 00000 n +0000121190 00000 n +0000121241 00000 n +0000121292 00000 n +0000121343 00000 n +0000121394 00000 n +0000121445 00000 n +0000121496 00000 n +0000121547 00000 n +0000121598 00000 n +0000121649 00000 n +0000121700 00000 n +0000121751 00000 n +0000121802 00000 n +0000121853 00000 n +0000121904 00000 n +0000121955 00000 n +0000122006 00000 n +0000122057 00000 n +0000122108 00000 n +0000122159 00000 n +0000122210 00000 n +0000122261 00000 n +0000122312 00000 n +0000122363 00000 n +0000122414 00000 n +0000122465 00000 n +0000122516 00000 n +0000122567 00000 n +0000122618 00000 n +0000122669 00000 n +0000122720 00000 n +0000122771 00000 n +0000122822 00000 n +0000122873 00000 n +0000122924 00000 n +0000122975 00000 n +0000123026 00000 n +0000123077 00000 n +0000123128 00000 n +0000123179 00000 n +0000123230 00000 n +0000123281 00000 n +0000123332 00000 n +0000123383 00000 n +0000123434 00000 n +0000123485 00000 n +0000123536 00000 n +0000123587 00000 n +0000123638 00000 n +0000123689 00000 n +0000123740 00000 n +0000123791 00000 n +0000123842 00000 n +0000123893 00000 n +0000123944 00000 n +0000123995 00000 n +0000124046 00000 n +0000124097 00000 n +0000124148 00000 n +0000124199 00000 n +0000124250 00000 n +0000124301 00000 n +0000124352 00000 n +0000124403 00000 n +0000124454 00000 n +0000124505 00000 n +0000124556 00000 n +0000124607 00000 n +0000124658 00000 n +0000124709 00000 n +0000124760 00000 n +0000124811 00000 n +0000124862 00000 n +0000124913 00000 n +0000124964 00000 n +0000125015 00000 n +0000125066 00000 n +0000125117 00000 n +0000125168 00000 n +0000125219 00000 n +0000125270 00000 n +0000125321 00000 n +0000125372 00000 n +0000125423 00000 n +0000125474 00000 n +0000125525 00000 n +0000125576 00000 n +0000125627 00000 n +0000125678 00000 n +0000125729 00000 n +0000125780 00000 n +0000125831 00000 n +0000125882 00000 n +0000125933 00000 n +0000125984 00000 n +0000126035 00000 n +0000126086 00000 n +0000126137 00000 n +0000126188 00000 n +0000126239 00000 n +0000126290 00000 n +0000126341 00000 n +0000126392 00000 n +0000126443 00000 n +0000126494 00000 n +0000126545 00000 n +0000126596 00000 n +0000126647 00000 n +0000126698 00000 n +0000126749 00000 n +0000126800 00000 n +0000126851 00000 n +0000126902 00000 n +0000126953 00000 n +0000127004 00000 n +0000127055 00000 n +0000127106 00000 n +0000127157 00000 n +0000127208 00000 n +0000127259 00000 n +0000127310 00000 n +0000127361 00000 n +0000127412 00000 n +0000127463 00000 n +0000127514 00000 n +0000127565 00000 n +0000127616 00000 n +0000127667 00000 n +0000127718 00000 n +0000127769 00000 n +0000127820 00000 n +0000127871 00000 n +0000127922 00000 n +0000127973 00000 n +0000128024 00000 n +0000128075 00000 n +0000128126 00000 n +0000128177 00000 n +0000128228 00000 n +0000128279 00000 n +0000128330 00000 n +0000128381 00000 n +0000128432 00000 n +0000128483 00000 n +0000128534 00000 n +0000128585 00000 n +0000128636 00000 n +0000128687 00000 n +0000128738 00000 n +0000128789 00000 n +0000128840 00000 n +0000128891 00000 n +0000128942 00000 n +0000128993 00000 n +0000129044 00000 n +0000129095 00000 n +0000129146 00000 n +0000129197 00000 n +0000129248 00000 n +0000129299 00000 n +0000129350 00000 n +0000129401 00000 n +0000129452 00000 n +0000129503 00000 n +0000129554 00000 n +0000129605 00000 n +0000129656 00000 n +0000129707 00000 n +0000129758 00000 n +0000129809 00000 n +0000129860 00000 n +0000129911 00000 n +0000129962 00000 n +0000130013 00000 n +0000130064 00000 n +0000130115 00000 n +0000130166 00000 n +0000130217 00000 n +0000130268 00000 n +0000130319 00000 n +0000130370 00000 n +0000130421 00000 n +0000130472 00000 n +0000130523 00000 n +0000130574 00000 n +0000130625 00000 n +0000130676 00000 n +0000130727 00000 n +0000130778 00000 n +0000130829 00000 n +0000130880 00000 n +0000130931 00000 n +0000130982 00000 n +0000131033 00000 n +0000131084 00000 n +0000131135 00000 n +0000131186 00000 n +0000131237 00000 n +0000131288 00000 n +0000131339 00000 n +0000131390 00000 n +0000131441 00000 n +0000131492 00000 n +0000131543 00000 n +0000131594 00000 n +0000131645 00000 n +0000131696 00000 n +0000131747 00000 n +0000131798 00000 n +0000131849 00000 n +0000131900 00000 n +0000131951 00000 n +0000132002 00000 n +0000132053 00000 n +0000132104 00000 n +0000132155 00000 n +0000132206 00000 n +0000132257 00000 n +0000132308 00000 n +0000132359 00000 n +0000132410 00000 n +0000132461 00000 n +0000132512 00000 n +0000132563 00000 n +0000132614 00000 n +0000132665 00000 n +0000132716 00000 n +0000132767 00000 n +0000132818 00000 n +0000132869 00000 n +0000132920 00000 n +0000132971 00000 n +0000133022 00000 n +0000133073 00000 n +0000133124 00000 n +0000133175 00000 n +0000133226 00000 n +0000133277 00000 n +0000133328 00000 n +0000133379 00000 n +0000133430 00000 n +0000133481 00000 n +0000133532 00000 n +0000133583 00000 n +0000133634 00000 n +0000133685 00000 n +0000133736 00000 n +0000133787 00000 n +0000133838 00000 n +0000133889 00000 n +0000133940 00000 n +0000133991 00000 n +0000134042 00000 n +0000134093 00000 n +0000134144 00000 n +0000134195 00000 n +0000134246 00000 n +0000134297 00000 n +0000134348 00000 n +0000134399 00000 n +0000134450 00000 n +0000134501 00000 n +0000134552 00000 n +0000134603 00000 n +0000134654 00000 n +0000134705 00000 n +0000134756 00000 n +0000134807 00000 n +0000134858 00000 n +0000134909 00000 n +0000134960 00000 n +0000135011 00000 n +0000135062 00000 n +0000135113 00000 n +0000135164 00000 n +0000135215 00000 n +0000135266 00000 n +0000135317 00000 n +0000135368 00000 n +0000135419 00000 n +0000135470 00000 n +0000135521 00000 n +0000135572 00000 n +0000135623 00000 n +0000135674 00000 n +0000135725 00000 n +0000135776 00000 n +0000135827 00000 n +0000135878 00000 n +0000135929 00000 n +0000135980 00000 n +0000136031 00000 n +0000136082 00000 n +0000136133 00000 n +0000136184 00000 n +0000136235 00000 n +0000136286 00000 n +0000136337 00000 n +0000136388 00000 n +0000136439 00000 n +0000136490 00000 n +0000136541 00000 n +0000136592 00000 n +0000136643 00000 n +0000136694 00000 n +0000136745 00000 n +0000136796 00000 n +0000136847 00000 n +0000136898 00000 n +0000136949 00000 n +0000137000 00000 n +0000137051 00000 n +0000137102 00000 n +0000137153 00000 n +0000137204 00000 n +0000137255 00000 n +0000137306 00000 n +0000137357 00000 n +0000137408 00000 n +0000137459 00000 n +0000137510 00000 n +0000137561 00000 n +0000137612 00000 n +0000137663 00000 n +0000137714 00000 n +0000137765 00000 n +0000137816 00000 n +0000137867 00000 n +0000137918 00000 n +0000137969 00000 n +0000138020 00000 n +0000138071 00000 n +0000138122 00000 n +0000138173 00000 n +0000138224 00000 n +0000138275 00000 n +0000138326 00000 n +0000138377 00000 n +0000138428 00000 n +0000138479 00000 n +0000138530 00000 n +0000138581 00000 n +0000138632 00000 n +0000138683 00000 n +0000138734 00000 n +0000138785 00000 n +0000138836 00000 n +0000138887 00000 n +0000138938 00000 n +0000138989 00000 n +0000139040 00000 n +0000139091 00000 n +0000139142 00000 n +0000139193 00000 n +0000139244 00000 n +0000139295 00000 n +0000139346 00000 n +0000139397 00000 n +0000139448 00000 n +0000139499 00000 n +0000139550 00000 n +0000139601 00000 n +0000139652 00000 n +0000139703 00000 n +0000139754 00000 n +0000139805 00000 n +0000139856 00000 n +0000139907 00000 n +0000139958 00000 n +0000140009 00000 n +0000140060 00000 n +0000140111 00000 n +0000140162 00000 n +0000140213 00000 n +0000140264 00000 n +0000140315 00000 n +0000140366 00000 n +0000140417 00000 n +0000140468 00000 n +0000140519 00000 n +0000140570 00000 n +0000140621 00000 n +0000140672 00000 n +0000140723 00000 n +0000140774 00000 n +0000140825 00000 n +0000140876 00000 n +0000140927 00000 n +0000140978 00000 n +0000141029 00000 n +0000141080 00000 n +0000141131 00000 n +0000141182 00000 n +0000141233 00000 n +0000141284 00000 n +0000141335 00000 n +0000141386 00000 n +0000141437 00000 n +0000141488 00000 n +0000141539 00000 n +0000141590 00000 n +0000141641 00000 n +0000141692 00000 n +0000141743 00000 n +0000141794 00000 n +0000141845 00000 n +0000141896 00000 n +0000141947 00000 n +0000141998 00000 n +0000142049 00000 n +0000142100 00000 n +0000142151 00000 n +0000142202 00000 n +0000142253 00000 n +0000142304 00000 n +0000142355 00000 n +0000142406 00000 n +0000142457 00000 n +0000142508 00000 n +0000142559 00000 n +0000142610 00000 n +0000142661 00000 n +0000142712 00000 n +0000142763 00000 n +0000142814 00000 n +0000142865 00000 n +0000142916 00000 n +0000142967 00000 n +0000143018 00000 n +0000143069 00000 n +0000143120 00000 n +0000143171 00000 n +0000143222 00000 n +0000143273 00000 n +0000143324 00000 n +0000143375 00000 n +0000143426 00000 n +0000143477 00000 n +0000143528 00000 n +0000143579 00000 n +0000143630 00000 n +0000143681 00000 n +0000143732 00000 n +0000143783 00000 n +0000143834 00000 n +0000143885 00000 n +0000143936 00000 n +0000143987 00000 n +0000144038 00000 n +0000144089 00000 n +0000144140 00000 n +0000144191 00000 n +0000144242 00000 n +0000144293 00000 n +0000144344 00000 n +0000144395 00000 n +0000144446 00000 n +0000144497 00000 n +0000144548 00000 n +0000144599 00000 n +0000144650 00000 n +0000144701 00000 n +0000144752 00000 n +0000144803 00000 n +0000144854 00000 n +0000144905 00000 n +0000144956 00000 n +0000145007 00000 n +0000145058 00000 n +0000145109 00000 n +0000145160 00000 n +0000145211 00000 n +0000145262 00000 n +0000145313 00000 n +0000145364 00000 n +0000145415 00000 n +0000145466 00000 n +0000145517 00000 n +0000145568 00000 n +0000145619 00000 n +0000145670 00000 n +0000145721 00000 n +0000145772 00000 n +0000145823 00000 n +0000145874 00000 n +0000145925 00000 n +0000145976 00000 n +0000146027 00000 n +0000146078 00000 n +0000146129 00000 n +0000146180 00000 n +0000146231 00000 n +0000146282 00000 n +0000146333 00000 n +0000146384 00000 n +0000146435 00000 n +0000146486 00000 n +0000146537 00000 n +0000146588 00000 n +0000146639 00000 n +0000146690 00000 n +0000146741 00000 n +0000146792 00000 n +0000146843 00000 n +0000146894 00000 n +0000146945 00000 n +0000146996 00000 n +0000147047 00000 n +0000147098 00000 n +0000147149 00000 n +0000147200 00000 n +0000147251 00000 n +0000147302 00000 n +0000147353 00000 n +0000147404 00000 n +0000147455 00000 n +0000147506 00000 n +0000147557 00000 n +0000147608 00000 n +0000147659 00000 n +0000147710 00000 n +0000147761 00000 n +0000147812 00000 n +0000147863 00000 n +0000147914 00000 n +0000147965 00000 n +0000148016 00000 n +0000148067 00000 n +0000148118 00000 n +0000148169 00000 n +0000148220 00000 n +0000148271 00000 n +0000148322 00000 n +0000148373 00000 n +0000148424 00000 n +0000148475 00000 n +0000148526 00000 n +0000148577 00000 n +0000148628 00000 n +0000148679 00000 n +0000148730 00000 n +0000148781 00000 n +0000148832 00000 n +0000148883 00000 n +0000148934 00000 n +0000148985 00000 n +0000149036 00000 n +0000149087 00000 n +0000149138 00000 n +0000149189 00000 n +0000149240 00000 n +0000149291 00000 n +0000149342 00000 n +0000149393 00000 n +0000149444 00000 n +0000149495 00000 n +0000149546 00000 n +0000149597 00000 n +0000149648 00000 n +0000149699 00000 n +0000149750 00000 n +0000149801 00000 n +0000149852 00000 n +0000149903 00000 n +0000149954 00000 n +0000150005 00000 n +0000150056 00000 n +0000150107 00000 n +0000150158 00000 n +0000150209 00000 n +0000150260 00000 n +0000150311 00000 n +0000150362 00000 n +0000150413 00000 n +0000150464 00000 n +0000150515 00000 n +0000150566 00000 n +0000150617 00000 n +0000150668 00000 n +0000150719 00000 n +0000150770 00000 n +0000150821 00000 n +0000150872 00000 n +0000150923 00000 n +0000150974 00000 n +0000151025 00000 n +0000151076 00000 n +0000151127 00000 n +0000151178 00000 n +0000151229 00000 n +0000151280 00000 n +0000151331 00000 n +0000151382 00000 n +0000151433 00000 n +0000151484 00000 n +0000151535 00000 n +0000151586 00000 n +0000151637 00000 n +0000151688 00000 n +0000151739 00000 n +0000151790 00000 n +0000151841 00000 n +0000151892 00000 n +0000151943 00000 n +0000151994 00000 n +0000152045 00000 n +0000152096 00000 n +0000152147 00000 n +0000152198 00000 n +0000152249 00000 n +0000152300 00000 n +0000152351 00000 n +0000152402 00000 n +0000152453 00000 n +0000152504 00000 n +0000152555 00000 n +0000152606 00000 n +0000152657 00000 n +0000152708 00000 n +0000152759 00000 n +0000152810 00000 n +0000152861 00000 n +0000152912 00000 n +0000152963 00000 n +0000153014 00000 n +0000153065 00000 n +0000153116 00000 n +0000153167 00000 n +0000153218 00000 n +0000153269 00000 n +0000153320 00000 n +0000153371 00000 n +0000153422 00000 n +0000153473 00000 n +0000153524 00000 n +0000153575 00000 n +0000153626 00000 n +0000153677 00000 n +0000153728 00000 n +0000153779 00000 n +0000153830 00000 n +0000155197 00000 n +0000155352 00000 n +0000161713 00000 n +0000161736 00000 n +0000161834 00000 n +0000161938 00000 n +0000161959 00000 n +0000162117 00000 n +0000163041 00000 n +0000163063 00000 n +0000163198 00000 n +0000163519 00000 n +0000163541 00000 n +0000163684 00000 n +0000164604 00000 n +0000164626 00000 n +0000164769 00000 n +0000166207 00000 n +0000166230 00000 n +0000166373 00000 n +0000167270 00000 n +0000167292 00000 n +0000167408 00000 n +0000167608 00000 n +0000167630 00000 n +0000167764 00000 n +0000168119 00000 n +0000168141 00000 n +0000168266 00000 n +0000168616 00000 n +0000168638 00000 n +0000168763 00000 n +0000169113 00000 n +0000169135 00000 n +0000169260 00000 n +0000169623 00000 n +0000169645 00000 n +0000169779 00000 n +0000170130 00000 n +0000170152 00000 n +0000170277 00000 n +0000170538 00000 n +0000170560 00000 n +0000170694 00000 n +0000171093 00000 n +0000171115 00000 n +0000171240 00000 n +0000171520 00000 n +0000171542 00000 n +0000171676 00000 n +0000172093 00000 n +0000172115 00000 n +0000172240 00000 n +0000172534 00000 n +0000172556 00000 n +0000172690 00000 n +0000172970 00000 n +0000172992 00000 n +0000173117 00000 n +0000173347 00000 n +0000173369 00000 n +0000173503 00000 n +0000173748 00000 n +0000173770 00000 n +0000173886 00000 n +0000174085 00000 n +0000174107 00000 n +0000174241 00000 n +0000174481 00000 n +0000174503 00000 n +0000174655 00000 n +0000175442 00000 n +0000175464 00000 n +0000175621 00000 n +0000175959 00000 n +0000175981 00000 n +0000176147 00000 n +0000176837 00000 n +0000176859 00000 n +0000177025 00000 n +0000178093 00000 n +0000178115 00000 n +0000178272 00000 n +0000179071 00000 n +0000179093 00000 n +0000179259 00000 n +0000180338 00000 n +0000180361 00000 n +0000180518 00000 n +0000181186 00000 n +0000181208 00000 n +0000181374 00000 n +0000182070 00000 n +0000182092 00000 n +0000182258 00000 n +0000182998 00000 n +0000183020 00000 n +0000183177 00000 n +0000183733 00000 n +0000183755 00000 n +0000183921 00000 n +0000184736 00000 n +0000184758 00000 n +0000184924 00000 n +0000185604 00000 n +0000185626 00000 n +0000185778 00000 n +0000186512 00000 n +0000186534 00000 n +0000186700 00000 n +0000187436 00000 n +0000187458 00000 n +0000187615 00000 n +0000188342 00000 n +0000188364 00000 n +0000188530 00000 n +0000189268 00000 n +0000189290 00000 n +0000189447 00000 n +0000189976 00000 n +0000189998 00000 n +0000190164 00000 n +0000190806 00000 n +0000190828 00000 n +0000190994 00000 n +0000191751 00000 n +0000191773 00000 n +0000191940 00000 n +0000192741 00000 n +0000192763 00000 n +0000192921 00000 n +0000193478 00000 n +0000193500 00000 n +0000193667 00000 n +0000194458 00000 n +0000194480 00000 n +0000194647 00000 n +0000195514 00000 n +0000195536 00000 n +0000195688 00000 n +0000196474 00000 n +0000196496 00000 n +0000196645 00000 n +0000196956 00000 n +0000196978 00000 n +0000197145 00000 n +0000197794 00000 n +0000197816 00000 n +0000197983 00000 n +0000198771 00000 n +0000198793 00000 n +0000198945 00000 n +0000199683 00000 n +0000199705 00000 n +0000199854 00000 n +0000200247 00000 n +0000200269 00000 n +0000200421 00000 n +0000201194 00000 n +0000201216 00000 n +0000201365 00000 n +0000201756 00000 n +0000201778 00000 n +0000201945 00000 n +0000202796 00000 n +0000202818 00000 n +0000202970 00000 n +0000203695 00000 n +0000203717 00000 n +0000203866 00000 n +0000204256 00000 n +0000204278 00000 n +0000204445 00000 n +0000205112 00000 n +0000205134 00000 n +0000205295 00000 n +0000205962 00000 n +0000205984 00000 n +0000206142 00000 n +0000206699 00000 n +0000206721 00000 n +0000206855 00000 n +0000207221 00000 n +0000207243 00000 n +0000207377 00000 n +0000207741 00000 n +0000207763 00000 n +0000207897 00000 n +0000208265 00000 n +0000208287 00000 n +0000208421 00000 n +0000208785 00000 n +0000208807 00000 n +0000208941 00000 n +0000209306 00000 n +0000209328 00000 n +0000209462 00000 n +0000209828 00000 n +0000209850 00000 n +0000209984 00000 n +0000210347 00000 n +0000210369 00000 n +0000210503 00000 n +0000210871 00000 n +0000210893 00000 n +0000211027 00000 n +0000211390 00000 n +0000211412 00000 n +0000211546 00000 n +0000211910 00000 n +0000211932 00000 n +0000212066 00000 n +0000212427 00000 n +0000212449 00000 n +0000212583 00000 n +0000212947 00000 n +0000212969 00000 n +0000213103 00000 n +0000213472 00000 n +0000213494 00000 n +0000213628 00000 n +0000213997 00000 n +0000214019 00000 n +0000214153 00000 n +0000214519 00000 n +0000214541 00000 n +0000214675 00000 n +0000215042 00000 n +0000215064 00000 n +0000215198 00000 n +0000215561 00000 n +0000215583 00000 n +0000215717 00000 n +0000216087 00000 n +0000216109 00000 n +0000216243 00000 n +0000216606 00000 n +0000216628 00000 n +0000216762 00000 n +0000217126 00000 n +0000217148 00000 n +0000217282 00000 n +0000217646 00000 n +0000217668 00000 n +0000217802 00000 n +0000218165 00000 n +0000218187 00000 n +0000218321 00000 n +0000218683 00000 n +0000218705 00000 n +0000218839 00000 n +0000219206 00000 n +0000219228 00000 n +0000219362 00000 n +0000219727 00000 n +0000219749 00000 n +0000219883 00000 n +0000220249 00000 n +0000220271 00000 n +0000220405 00000 n +0000220768 00000 n +0000220790 00000 n +0000220924 00000 n +0000221289 00000 n +0000221311 00000 n +0000221445 00000 n +0000221809 00000 n +0000221831 00000 n +0000221965 00000 n +0000222333 00000 n +0000222355 00000 n +0000222489 00000 n +0000222856 00000 n +0000222878 00000 n +0000223012 00000 n +0000223376 00000 n +0000223398 00000 n +0000223532 00000 n +0000223899 00000 n +0000223921 00000 n +0000224055 00000 n +0000224424 00000 n +0000224446 00000 n +0000224580 00000 n +0000224945 00000 n +0000224967 00000 n +0000225101 00000 n +0000225468 00000 n +0000225490 00000 n +0000225624 00000 n +0000225991 00000 n +0000226013 00000 n +0000226147 00000 n +0000226516 00000 n +0000226538 00000 n +0000226672 00000 n +0000227039 00000 n +0000227061 00000 n +0000227195 00000 n +0000227561 00000 n +0000227583 00000 n +0000227717 00000 n +0000228083 00000 n +0000228105 00000 n +0000228239 00000 n +0000228607 00000 n +0000228629 00000 n +0000228763 00000 n +0000229125 00000 n +0000229147 00000 n +0000229281 00000 n +0000229650 00000 n +0000229672 00000 n +0000229806 00000 n +0000230170 00000 n +0000230192 00000 n +0000230326 00000 n +0000230689 00000 n +0000230711 00000 n +0000230845 00000 n +0000231206 00000 n +0000231228 00000 n +0000231362 00000 n +0000231725 00000 n +0000231747 00000 n +0000231881 00000 n +0000232246 00000 n +0000232268 00000 n +0000232402 00000 n +0000232768 00000 n +0000232790 00000 n +0000232924 00000 n +0000233285 00000 n +0000233307 00000 n +0000233441 00000 n +0000233808 00000 n +0000233830 00000 n +0000233964 00000 n +0000234326 00000 n +0000234348 00000 n +0000234482 00000 n +0000234846 00000 n +0000234868 00000 n +0000235002 00000 n +0000235368 00000 n +0000235390 00000 n +0000235524 00000 n +0000235896 00000 n +0000235918 00000 n +0000236052 00000 n +0000236417 00000 n +0000236439 00000 n +0000236573 00000 n +0000236941 00000 n +0000236963 00000 n +0000237097 00000 n +0000237464 00000 n +0000237486 00000 n +0000237620 00000 n +0000237988 00000 n +0000238010 00000 n +0000238144 00000 n +0000238507 00000 n +0000238529 00000 n +0000238663 00000 n +0000239029 00000 n +0000239051 00000 n +0000239185 00000 n +0000239546 00000 n +0000239568 00000 n +0000239702 00000 n +0000240070 00000 n +0000240092 00000 n +0000240226 00000 n +0000240591 00000 n +0000240613 00000 n +0000240747 00000 n +0000241116 00000 n +0000241138 00000 n +0000241296 00000 n +0000243865 00000 n +0000243888 00000 n +0000244046 00000 n +0000246270 00000 n +0000246293 00000 n +0000246451 00000 n +0000247834 00000 n +0000247857 00000 n +0000248006 00000 n +0000249282 00000 n +0000249305 00000 n +0000249454 00000 n +0000250710 00000 n +0000250733 00000 n +0000250882 00000 n +0000252174 00000 n +0000252197 00000 n +0000252346 00000 n +0000253644 00000 n +0000253667 00000 n +0000253816 00000 n +0000255102 00000 n +0000255125 00000 n +0000255274 00000 n +0000256574 00000 n +0000256597 00000 n +0000256746 00000 n +0000258007 00000 n +0000258030 00000 n +0000258179 00000 n +0000259470 00000 n +0000259493 00000 n +0000259642 00000 n +0000260927 00000 n +0000260950 00000 n +0000261099 00000 n +0000262394 00000 n +0000262417 00000 n +0000262566 00000 n +0000263843 00000 n +0000263866 00000 n +0000264015 00000 n +0000265305 00000 n +0000265328 00000 n +0000265477 00000 n +0000266774 00000 n +0000266797 00000 n +0000266946 00000 n +0000267403 00000 n +0000267425 00000 n +0000267541 00000 n +0000267723 00000 n +0000267745 00000 n +0000267804 00000 n +0000267913 00000 n +0000268064 00000 n +0000268171 00000 n +0000268280 00000 n +0000268452 00000 n +0000268564 00000 n +0000268684 00000 n +0000268794 00000 n +0000268907 00000 n +0000269020 00000 n +0000269141 00000 n +0000269243 00000 n +0000269403 00000 n +0000269549 00000 n +0000269665 00000 n +0000269823 00000 n +0000269928 00000 n +0000270076 00000 n +0000270196 00000 n +0000270325 00000 n +0000270432 00000 n +0000270589 00000 n +0000270694 00000 n +0000270822 00000 n +0000270950 00000 n +0000271073 00000 n +0000271205 00000 n +0000271331 00000 n +0000271443 00000 n +0000271600 00000 n +0000271705 00000 n +0000271834 00000 n +0000271957 00000 n +0000272085 00000 n +0000272214 00000 n +0000272338 00000 n +0000272470 00000 n +0000272599 00000 n +0000272729 00000 n +0000272846 00000 n +0000273007 00000 n +0000273112 00000 n +0000273246 00000 n +0000273381 00000 n +0000273498 00000 n +0000273640 00000 n +0000273745 00000 n +0000273869 00000 n +0000273993 00000 n +0000274116 00000 n +0000274241 00000 n +0000274362 00000 n +0000274490 00000 n +0000274597 00000 n +0000274760 00000 n +0000274898 00000 n +0000275013 00000 n +0000275134 00000 n +0000275241 00000 n +0000275407 00000 n +0000275500 00000 n +0000275627 00000 n +0000275740 00000 n +0000275911 00000 n +0000276049 00000 n +0000276156 00000 n +0000276264 00000 n +0000276424 00000 n +0000276534 00000 n +0000276664 00000 n +0000276794 00000 n +0000276905 00000 n +0000277020 00000 n +0000277184 00000 n +0000277322 00000 n +0000277437 00000 n +0000277558 00000 n +0000277679 00000 n +0000277778 00000 n +0000277944 00000 n +0000278037 00000 n +0000278164 00000 n +0000278285 00000 n +0000278442 00000 n +0000278548 00000 n +0000278668 00000 n +0000278787 00000 n +0000278911 00000 n +0000279030 00000 n +0000279138 00000 n +0000279296 00000 n +0000279374 00000 n +0000279518 00000 n +0000279665 00000 n +0000279762 00000 n +0000279877 00000 n +0000279990 00000 n +0000280107 00000 n +0000280220 00000 n +0000280320 00000 n +0000280481 00000 n +0000280578 00000 n +0000280693 00000 n +0000280806 00000 n +0000280923 00000 n +0000281036 00000 n +0000281136 00000 n +0000281301 00000 n +0000281398 00000 n +0000281513 00000 n +0000281626 00000 n +0000281743 00000 n +0000281856 00000 n +0000281956 00000 n +0000282117 00000 n +0000282214 00000 n +0000282329 00000 n +0000282442 00000 n +0000282559 00000 n +0000282672 00000 n +0000282772 00000 n +0000282935 00000 n +0000283032 00000 n +0000283147 00000 n +0000283264 00000 n +0000283377 00000 n +0000283477 00000 n +0000283639 00000 n +0000283736 00000 n +0000283851 00000 n +0000283964 00000 n +0000284081 00000 n +0000284194 00000 n +0000284294 00000 n +0000284456 00000 n +0000284553 00000 n +0000284666 00000 n +0000284783 00000 n +0000284896 00000 n +0000284996 00000 n +0000285157 00000 n +0000285254 00000 n +0000285369 00000 n +0000285482 00000 n +0000285599 00000 n +0000285699 00000 n +0000285862 00000 n +0000285959 00000 n +0000286074 00000 n +0000286187 00000 n +0000286304 00000 n +0000286417 00000 n +0000286517 00000 n +0000286675 00000 n +0000286772 00000 n +0000286887 00000 n +0000287000 00000 n +0000287117 00000 n +0000287216 00000 n +0000287379 00000 n +0000287476 00000 n +0000287591 00000 n +0000287704 00000 n +0000287821 00000 n +0000287934 00000 n +0000288034 00000 n +0000288197 00000 n +0000288294 00000 n +0000288407 00000 n +0000288524 00000 n +0000288637 00000 n +0000288737 00000 n +0000288901 00000 n +0000288998 00000 n +0000289113 00000 n +0000289226 00000 n +0000289343 00000 n +0000289456 00000 n +0000289556 00000 n +0000289717 00000 n +0000289814 00000 n +0000289931 00000 n +0000290044 00000 n +0000290144 00000 n +0000290304 00000 n +0000290401 00000 n +0000290516 00000 n +0000290633 00000 n +0000290746 00000 n +0000290846 00000 n +0000291005 00000 n +0000291102 00000 n +0000291217 00000 n +0000291330 00000 n +0000291447 00000 n +0000291560 00000 n +0000291660 00000 n +0000291822 00000 n +0000291919 00000 n +0000292034 00000 n +0000292147 00000 n +0000292264 00000 n +0000292377 00000 n +0000292477 00000 n +0000292638 00000 n +0000292735 00000 n +0000292848 00000 n +0000292965 00000 n +0000293078 00000 n +0000293178 00000 n +0000293341 00000 n +0000293438 00000 n +0000293553 00000 n +0000293666 00000 n +0000293783 00000 n +0000293896 00000 n +0000293996 00000 n +0000294160 00000 n +0000294257 00000 n +0000294372 00000 n +0000294485 00000 n +0000294602 00000 n +0000294715 00000 n +0000294815 00000 n +0000294976 00000 n +0000295073 00000 n +0000295188 00000 n +0000295301 00000 n +0000295418 00000 n +0000295531 00000 n +0000295631 00000 n +0000295794 00000 n +0000295891 00000 n +0000296006 00000 n +0000296123 00000 n +0000296236 00000 n +0000296336 00000 n +0000296498 00000 n +0000296595 00000 n +0000296710 00000 n +0000296823 00000 n +0000296940 00000 n +0000297053 00000 n +0000297153 00000 n +0000297321 00000 n +0000297418 00000 n +0000297533 00000 n +0000297646 00000 n +0000297763 00000 n +0000297876 00000 n +0000297976 00000 n +0000298144 00000 n +0000298241 00000 n +0000298356 00000 n +0000298469 00000 n +0000298586 00000 n +0000298699 00000 n +0000298799 00000 n +0000298968 00000 n +0000299065 00000 n +0000299180 00000 n +0000299293 00000 n +0000299410 00000 n +0000299523 00000 n +0000299623 00000 n +0000299792 00000 n +0000299889 00000 n +0000300004 00000 n +0000300117 00000 n +0000300234 00000 n +0000300347 00000 n +0000300447 00000 n +0000300605 00000 n +0000300702 00000 n +0000300815 00000 n +0000300932 00000 n +0000301045 00000 n +0000301145 00000 n +0000301305 00000 n +0000301402 00000 n +0000301517 00000 n +0000301630 00000 n +0000301747 00000 n +0000301846 00000 n +0000302002 00000 n +0000302099 00000 n +0000302212 00000 n +0000302329 00000 n +0000302442 00000 n +0000302542 00000 n +0000302702 00000 n +0000302799 00000 n +0000302914 00000 n +0000303027 00000 n +0000303144 00000 n +0000303257 00000 n +0000303357 00000 n +0000303514 00000 n +0000303611 00000 n +0000303726 00000 n +0000303839 00000 n +0000303956 00000 n +0000304069 00000 n +0000304169 00000 n +0000304332 00000 n +0000304429 00000 n +0000304544 00000 n +0000304657 00000 n +0000304774 00000 n +0000304887 00000 n +0000304987 00000 n +0000305144 00000 n +0000305241 00000 n +0000305356 00000 n +0000305469 00000 n +0000305586 00000 n +0000305699 00000 n +0000305799 00000 n +0000305958 00000 n +0000306055 00000 n +0000306170 00000 n +0000306283 00000 n +0000306400 00000 n +0000306513 00000 n +0000306613 00000 n +0000306773 00000 n +0000306870 00000 n +0000306985 00000 n +0000307098 00000 n +0000307215 00000 n +0000307328 00000 n +0000307428 00000 n +0000307586 00000 n +0000307683 00000 n +0000307798 00000 n +0000307911 00000 n +0000308028 00000 n +0000308141 00000 n +0000308241 00000 n +0000308401 00000 n +0000308498 00000 n +0000308613 00000 n +0000308726 00000 n +0000308843 00000 n +0000308956 00000 n +0000309056 00000 n +0000309213 00000 n +0000309310 00000 n +0000309425 00000 n +0000309538 00000 n +0000309655 00000 n +0000309768 00000 n +0000309868 00000 n +0000310025 00000 n +0000310122 00000 n +0000310237 00000 n +0000310350 00000 n +0000310467 00000 n +0000310580 00000 n +0000310680 00000 n +0000310835 00000 n +0000310932 00000 n +0000311047 00000 n +0000311160 00000 n +0000311277 00000 n +0000311390 00000 n +0000311490 00000 n +0000311646 00000 n +0000311743 00000 n +0000311858 00000 n +0000311971 00000 n +0000312088 00000 n +0000312201 00000 n +0000312301 00000 n +0000312466 00000 n +0000312563 00000 n +0000312678 00000 n +0000312791 00000 n +0000312908 00000 n +0000313021 00000 n +0000313121 00000 n +0000313284 00000 n +0000313381 00000 n +0000313496 00000 n +0000313609 00000 n +0000313726 00000 n +0000313839 00000 n +0000313939 00000 n +0000314099 00000 n +0000314196 00000 n +0000314311 00000 n +0000314424 00000 n +0000314541 00000 n +0000314654 00000 n +0000314754 00000 n +0000314915 00000 n +0000315012 00000 n +0000315127 00000 n +0000315240 00000 n +0000315357 00000 n +0000315470 00000 n +0000315570 00000 n +0000315726 00000 n +0000315823 00000 n +0000315938 00000 n +0000316051 00000 n +0000316168 00000 n +0000316281 00000 n +0000316381 00000 n +0000316543 00000 n +0000316640 00000 n +0000316755 00000 n +0000316868 00000 n +0000316985 00000 n +0000317098 00000 n +0000317198 00000 n +0000317357 00000 n +0000317454 00000 n +0000317569 00000 n +0000317682 00000 n +0000317799 00000 n +0000317912 00000 n +0000318012 00000 n +0000318168 00000 n +0000318265 00000 n +0000318380 00000 n +0000318493 00000 n +0000318610 00000 n +0000318723 00000 n +0000318823 00000 n +0000318981 00000 n +0000319078 00000 n +0000319193 00000 n +0000319306 00000 n +0000319423 00000 n +0000319536 00000 n +0000319636 00000 n +0000319791 00000 n +0000319888 00000 n +0000320003 00000 n +0000320116 00000 n +0000320233 00000 n +0000320346 00000 n +0000320446 00000 n +0000320602 00000 n +0000320699 00000 n +0000320814 00000 n +0000320927 00000 n +0000321044 00000 n +0000321157 00000 n +0000321257 00000 n +0000321418 00000 n +0000321515 00000 n +0000321630 00000 n +0000321743 00000 n +0000321860 00000 n +0000321973 00000 n +0000322073 00000 n +0000322233 00000 n +0000322330 00000 n +0000322445 00000 n +0000322558 00000 n +0000322675 00000 n +0000322788 00000 n +0000322888 00000 n +0000323048 00000 n +0000323145 00000 n +0000323260 00000 n +0000323373 00000 n +0000323490 00000 n +0000323603 00000 n +0000323703 00000 n +0000323860 00000 n +0000323957 00000 n +0000324072 00000 n +0000324185 00000 n +0000324302 00000 n +0000324415 00000 n +0000324515 00000 n +0000324673 00000 n +0000324770 00000 n +0000324885 00000 n +0000324998 00000 n +0000325115 00000 n +0000325228 00000 n +0000325328 00000 n +0000325485 00000 n +0000325582 00000 n +0000325697 00000 n +0000325810 00000 n +0000325927 00000 n +0000326040 00000 n +0000326140 00000 n +0000326301 00000 n +0000326398 00000 n +0000326513 00000 n +0000326626 00000 n +0000326743 00000 n +0000326856 00000 n +0000326956 00000 n +0000327118 00000 n +0000327215 00000 n +0000327330 00000 n +0000327443 00000 n +0000327560 00000 n +0000327673 00000 n +0000327773 00000 n +0000327931 00000 n +0000328028 00000 n +0000328143 00000 n +0000328256 00000 n +0000328373 00000 n +0000328486 00000 n +0000328586 00000 n +0000328747 00000 n +0000328844 00000 n +0000328959 00000 n +0000329072 00000 n +0000329189 00000 n +0000329302 00000 n +0000329402 00000 n +0000329564 00000 n +0000329661 00000 n +0000329776 00000 n +0000329889 00000 n +0000330006 00000 n +0000330119 00000 n +0000330219 00000 n +0000330378 00000 n +0000330475 00000 n +0000330590 00000 n +0000330703 00000 n +0000330820 00000 n +0000330933 00000 n +0000331033 00000 n +0000331193 00000 n +0000331290 00000 n +0000331405 00000 n +0000331518 00000 n +0000331635 00000 n +0000331748 00000 n +0000331848 00000 n +0000332012 00000 n +0000332109 00000 n +0000332224 00000 n +0000332337 00000 n +0000332454 00000 n +0000332567 00000 n +0000332667 00000 n +0000332832 00000 n +0000332929 00000 n +0000333044 00000 n +0000333157 00000 n +0000333274 00000 n +0000333387 00000 n +0000333487 00000 n +0000333650 00000 n +0000333747 00000 n +0000333862 00000 n +0000333975 00000 n +0000334092 00000 n +0000334205 00000 n +0000334305 00000 n +0000334465 00000 n +0000334562 00000 n +0000334677 00000 n +0000334790 00000 n +0000334907 00000 n +0000335020 00000 n +0000335120 00000 n +0000335281 00000 n +0000335378 00000 n +0000335493 00000 n +0000335606 00000 n +0000335723 00000 n +0000335836 00000 n +0000335936 00000 n +0000336097 00000 n +0000336194 00000 n +0000336309 00000 n +0000336422 00000 n +0000336539 00000 n +0000336652 00000 n +0000336752 00000 n +0000336909 00000 n +0000337006 00000 n +0000337121 00000 n +0000337234 00000 n +0000337351 00000 n +0000337464 00000 n +0000337564 00000 n +0000337728 00000 n +0000337825 00000 n +0000337940 00000 n +0000338053 00000 n +0000338170 00000 n +0000338283 00000 n +0000338383 00000 n +0000338540 00000 n +0000338637 00000 n +0000338752 00000 n +0000338865 00000 n +0000338982 00000 n +0000339095 00000 n +0000339195 00000 n +0000339349 00000 n +0000339446 00000 n +0000339561 00000 n +0000339674 00000 n +0000339791 00000 n +0000339904 00000 n +0000340004 00000 n +0000340159 00000 n +0000340256 00000 n +0000340371 00000 n +0000340484 00000 n +0000340601 00000 n +0000340714 00000 n +0000340814 00000 n +0000340969 00000 n +0000341066 00000 n +0000341181 00000 n +0000341294 00000 n +0000341411 00000 n +0000341524 00000 n +0000341624 00000 n +0000341785 00000 n +0000341882 00000 n +0000341997 00000 n +0000342110 00000 n +0000342227 00000 n +0000342340 00000 n +0000342440 00000 n +0000342596 00000 n +0000342693 00000 n +0000342808 00000 n +0000342921 00000 n +0000343038 00000 n +0000343151 00000 n +0000343251 00000 n +0000343407 00000 n +0000343504 00000 n +0000343619 00000 n +0000343732 00000 n +0000343849 00000 n +0000343962 00000 n +0000344062 00000 n +0000344222 00000 n +0000344319 00000 n +0000344434 00000 n +0000344547 00000 n +0000344664 00000 n +0000344777 00000 n +0000344877 00000 n +0000345034 00000 n +0000345131 00000 n +0000345246 00000 n +0000345359 00000 n +0000345476 00000 n +0000345589 00000 n +0000345689 00000 n +0000345844 00000 n +0000345941 00000 n +0000346056 00000 n +0000346169 00000 n +0000346286 00000 n +0000346399 00000 n +0000346499 00000 n +0000346660 00000 n +0000346757 00000 n +0000346872 00000 n +0000346985 00000 n +0000347102 00000 n +0000347215 00000 n +0000347315 00000 n +0000347482 00000 n +0000347579 00000 n +0000347694 00000 n +0000347807 00000 n +0000347924 00000 n +0000348037 00000 n +0000348137 00000 n +0000348298 00000 n +0000348395 00000 n +0000348510 00000 n +0000348623 00000 n +0000348740 00000 n +0000348853 00000 n +0000348953 00000 n +0000349112 00000 n +0000349209 00000 n +0000349324 00000 n +0000349437 00000 n +0000349554 00000 n +0000349667 00000 n +0000349767 00000 n +0000349930 00000 n +0000350027 00000 n +0000350142 00000 n +0000350255 00000 n +0000350372 00000 n +0000350485 00000 n +0000350585 00000 n +0000350746 00000 n +0000350843 00000 n +0000350958 00000 n +0000351071 00000 n +0000351188 00000 n +0000351301 00000 n +0000351401 00000 n +0000351558 00000 n +0000351655 00000 n +0000351770 00000 n +0000351883 00000 n +0000352000 00000 n +0000352113 00000 n +0000352213 00000 n +0000352372 00000 n +0000352469 00000 n +0000352584 00000 n +0000352697 00000 n +0000352814 00000 n +0000352927 00000 n +0000353027 00000 n +0000353182 00000 n +0000353279 00000 n +0000353394 00000 n +0000353507 00000 n +0000353624 00000 n +0000353737 00000 n +0000353837 00000 n +0000353998 00000 n +0000354095 00000 n +0000354210 00000 n +0000354323 00000 n +0000354440 00000 n +0000354553 00000 n +0000354653 00000 n +0000354812 00000 n +0000354909 00000 n +0000355024 00000 n +0000355137 00000 n +0000355254 00000 n +0000355367 00000 n +0000355467 00000 n +0000355613 00000 n +0000355710 00000 n +0000355825 00000 n +0000355938 00000 n +0000356055 00000 n +0000356168 00000 n +0000356268 00000 n +trailer +<> +startxref +356501 +%%EOF diff --git a/doc/spm.shtml b/doc/spm.shtml new file mode 100644 index 0000000000..4e361fc9c9 --- /dev/null +++ b/doc/spm.shtml @@ -0,0 +1,4202 @@ + + + + + + DRAFT - CUPS Software Programmers Manual + + + +

Preface

+ +This software programmers manual provides software programming +information for the Common UNIX Printing System ("CUPS") Version 1.1. + + + +

Document Overview

+ +

This software administrators manual is organized into the following sections:

+ +
    +
  • 1 - Printing System Overview
  • +
  • 2 - The CUPS API
  • +
  • 3 - Writing Filters
  • +
  • 4 - Writing Printer Drivers
  • +
  • 5 - Writing Backends
  • +
  • A - Constants
  • +
  • B - Structures
  • +
  • C - Functions
  • +
+ +

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 - The CUPS API

+ +

This chapter describes the CUPS Application Programmers Interface ("API"). + +

The CUPS Library

+ +

Detecting the CUPS Library in Autoconf

+ + +

Basic Services

+ +

Include Files

+ +

Getting the Available Printers and Classes

+ +

Printing Files

+ +

Setting Printer Options

+ +

Cancelling Jobs

+ + +

HTTP Services

+ +

Include Files

+ +

Connecting to a Server

+ +

Setting Request Fields

+ +

Issuing a Request

+ +

Getting the Request Status

+ +

Sending Request Data

+ +

Reading Request Data

+ + +

IPP Services

+ +

Include Files

+ +

Creating an IPP Request

+ +

Adding Attributes

+ +

Sending an IPP Request

+ +

Reading an IPP Response

+ +

Finding Attributes

+ +

Looping Through Attributes

+ +

IPP Standard Operations

+ +

IPP Extension Operations

+ +

CUPS Extension Operations

+ + +

Language Services

+ +

Include Files

+ +

Getting the Default Language

+ +

Getting the Language Encoding

+ +

Getting a Language String

+ + +

PPD Services

+ +

Include Files

+ +

Loading a PPD File

+ +

Options and Groups

+ +

Finding an Option

+ +

Finding a Page Size

+ +

Marking Options

+ +

Checking for Conflicts

+ +

Sending Options

+ + +

3 - Writing Filters

+ +

This chapter describes how to write a file filter for CUPS. + +

Overview

+ +

Security Considerations

+ +Users and Groups + +

Temporary Files

+ +

Page Accounting

+ + +

Command-Line Arguments

+ +

Copy Generation

+ + +

Environment Variables

+ + +

Writing a HTML Filter

+ + +

4 - Writing Printer Drivers

+ +

This chapter discusses how to write a printer driver, which is a +special filter program that converts CUPS raster data into the +appropriate commands and data required for a printer. + +

Overview

+ +

Page Accounting

+ +

Color Management

+ + +

Raster Functions

+ +

cupsRasterOpen()

+ +

cupsRasterReadHeader()

+ +

cupsRasterReadPixels()

+ +

cupsRasterClose()

+ + +

Writing a HP-PCL Driver

+ + +

5 - Writing Backends

+ +

This chapter describes how to write a backend for CUPS. Backends +communicate directly with printers and allow printer drivers and +filters to send data using any type of connection transparently. + +

Overview

+ +

Security Considerations

+ +Users and Groups + +

Temporary Files

+ +

Page Accounting

+ +

Retries

+ + +

Command-Line Arguments

+ +

Copy Generation

+ + +

Environment Variables

+ + +

Writing a Serial Port Backend

+ + +

A - Constants

+ +

This appendix lists all of the constants that are defined by the CUPS +API. + +

CUPS Constants

+ +

HTTP Constants

+ +

IPP Constants

+ +

Language Constants

+ +

PPD Constants

+ +

Raster Constants

+ + +

B - Structures

+ +

This appendix describes all of the structures that are defined by the CUPS +API. + +

+ + +

C - Functions

+ +

This appendix provides a reference for all of the CUPS API functions. + +

cupsAddOption()

+ +

Usage

+ +
+int
+cupsAddOption(const char *name,
+              const char *value,
+              int num_options,
+	      cups_option_t **options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
nameThe name of the option.
valueThe value of the option.
num_optionsNumber of options currently in the array.
optionsPointer to the options array.
+ +

Returns

+ +

The new number of options. + +

Description

+ +

cupsAddOption() adds an option to the specified array. + +

Example

+ +
+#include <cups.h>
+
+...
+
+/* Declare the options array */
+int           num_options;
+cups_option_t *options;
+
+/* Initialize the options array */
+num_options = 0;
+options     = (cups_option_t *)0;
+
+/* Add options using cupsAddOption() */
+num_options = cupsAddOption("media", "letter", num_options, &options);
+num_options = cupsAddOption("resolution", "300dpi", num_options, &options);
+
+ +

See Also

+ +cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + +

cupsCancelJob()

+ +

Usage

+ +
+int
+cupsCancelJob(const char *dest,
+              int job);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
destPrinter or class name
jobJob ID
+ +

Returns

+ +

1 on success, 0 on failure. On failure the error can be found by calling +cupsLastError(). + +

Description

+ +

cupsCancelJob() cancels the specifies job. + +

Example

+ +
+#include <cups.h>
+
+cupsCancelJob("LaserJet", 1);
+
+ +

See Also

+ +

+cupsLastError(), +cupsPrintFile() + +

cupsDoFileRequest()

+ +

Usage

+ +
+ipp_t *
+cupsDoFileRequest(http_t *http,
+                  ipp_t *request,
+                  const char *resource,
+		  const char *filename);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
filenameFile to send with POST request (NULL pointer if none.)
+ +

Returns

+ +

IPP response data or NULL if the request fails. On failure +the error can be found by calling +cupsLastError(). + +

Description

+ +

cupsDoFileRequest() does a HTTP POST request and provides the +IPP request and optionally the contents of a file to the IPP server. It also +handles resubmitting the request and performing password authentication as +needed. + +

Example

+ +
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_PRINT_FILE;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+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, "ipp://hostname/resource");
+
+ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
+             NULL, cupsUser());
+
+/* Do the request... */
+response = cupsDoFileRequest(http, request, "/resource", "filename.txt");
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), +httpConnect(), +ippAddString(), +ippNew() + +

cupsDoRequest()

+ +

Usage

+ +
+ipp_t *
+cupsDoRequest(http_t *http,
+              ipp_t *request,
+              const char *resource);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
httpHTTP connection to server.
requestIPP request data.
resourceHTTP resource name for POST.
+ +

Returns

+ +

IPP response data or NULL if the request fails. On failure +the error can be found by calling +cupsLastError(). + +

Description

+ +

cupsDoRequest() does a HTTP POST request and provides +the IPP request to the IPP server. It also handles resubmitting the +request and performing password authentication as needed. + +

Example

+ +
+#include <cups.h>
+
+http_t      *http;
+cups_lang_t *language;
+ipp_t       *request;
+ipp_t       *response;
+
+...
+
+/* Get the default language */
+language = cupsLangDefault();
+
+/* Create a new IPP request */
+request  = ippNew();
+
+request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
+request->request.op.request_id   = 1;
+
+/* Add required attributes */
+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, "ipp://hostname/resource");
+
+/* Do the request... */
+response = cupsDoRequest(http, request, "/resource");
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), +httpConnect(), +ippAddString(), +ippNew() + +

cupsFreeOptions()

+ +

Usage

+ +
+void
+cupsFreeOptions(int num_options,
+                cups_option_t *options);
+
+

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
num_optionsNumber of options in array.
optionsPointer to options array.
+ +

Description

+ +

cupsFreeOptions() frees all memory associated with the +option array specified. + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+cupsFreeOptions(num_options, options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsGetOption(), +cupsMarkOptions(), +cupsParseOptions() + +

cupsGetClasses()

+ +

Usage

+ +
+int
+cupsGetClasses(char ***classes);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
classesPointer to character pointer array.
+ +

Returns

+ +

The number of printer classes available. + +

Description

+ +

cupsGetClasses() gets a list of the available printer classes. +The returned array should be freed using the free() when it is +no longer needed. + +

Example

+ +
+#include <cups/cups.h>
+
+int  i;
+int  num_classes;
+char **classes;
+
+...
+
+num_classes = cupsGetClasses(&classes);
+
+...
+
+if (num_classes > 0)
+{
+  for (i = 0; i < num_classes; i ++)
+    free(classes[i]);
+
+  free(classes);
+}
+
+ +

See Also

+ +

+cupsGetDefault(), +cupsGetPrinters() + +

cupsGetDefault()

+ +

Usage

+ +
+const char *
+cupsGetDefault(void);
+
+ +

Returns

+ +

A pointer to the default destination. + +

Description

+ +

cupsGetDefault() gets the default destination printer or class. +The default destination is stored in a static string and will be overwritten +(usually with the same value) after each call. + +

Example

+ +
+#include <cups/cups.h>
+
+printf("The default destination is %s\n", cupsGetDefault());
+
+ +

See Also

+ +

+cupsGetClasses(), +cupsGetPrinters() + +

cupsGetOption()

+ +

Usage

+ +
+const char *
+cupsGetOption(const char *name,
+              int num_options,
+              cups_option_t *options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
nameThe name of the option.
num_optionsThe number of options in the array.
optionsThe options array.
+ +

Returns

+ +

A pointer to the option values or NULL if the option is +not defined. + +

Description

+ +

cupsGetOption() returns the first occurrence of the +named option. If the option is not included in the options array then a +NULL pointer is returned. + +

+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+const char    *media;
+
+...
+
+media = cupsGetOption("media", num_options, options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsFreeOptions(), +cupsMarkOptions(), +cupsParseOptions() + +

cupsGetPassword()

+ +

Usage

+ +
+const char *
+cupsGetPassword(const char *prompt);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
promptThe prompt to display to the user.
+ +

Returns

+ +

A pointer to the password that was entered or NULL if no +password was entered. + +

Description

+ +

cupsGetPassword() displays the prompt string and asks the user +for a password. The password text is not echoed to the user. + +

Example

+ +
+#include <cups/cups.h>
+
+char *password;
+
+...
+
+password = cupsGetPassword("Please enter a password:");
+
+ +

See Also

+ +

+cupsServer(), +cupsUser() + +

cupsGetPPD()

+ +

Usage

+ +
+const char *
+cupsGetPPD(const char *printer);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
printerThe name of the printer.
+ +

Returns

+ +

The name of a temporary file containing the PPD file or NULL +if the printer cannot be located or does not have a PPD file. + +

Description

+ +

cupsGetPPD() gets a copy of the PPD file for the named printer. +The printer name can be of the form "printer" or "printer@hostname". + +

You should remove (unlink) the PPD file after you are done using it. The +filename is stored in a static buffer and will be overwritten with each call +to cupsGetPPD(). + +

Example

+ +
+#include <cups/cups.h>
+
+char *ppd;
+
+...
+
+ppd = cupsGetPPD("printer@hostname");
+
+...
+
+unlink(ppd);
+
+ +

cupsGetPrinters()

+ +

Usage

+ +
+int
+cupsGetPrinters(char ***printers);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
printersPointer to character pointer array.
+ +

Returns

+ +

The number of printer printers available. + +

Description

+ +

cupsGetPrinters() gets a list of the available printers. +The returned array should be freed using the free() when it is +no longer needed. + +

Example

+ +
+#include <cups/cups.h>
+
+int  i;
+int  num_printers;
+char **printers;
+
+...
+
+num_printers = cupsGetPrinters(&printers);
+
+...
+
+if (num_printers > 0)
+{
+  for (i = 0; i < num_printers; i ++)
+    free(printers[i]);
+
+  free(printers);
+}
+
+ +

See Also

+ +

+cupsGetClasses(), +cupsGetDefault() + +

cupsLangDefault()

+ +

Usage

+ +
+const char *
+cupsLangDefault(void);
+
+ +

Returns

+ +

A pointer to the default language structure. + +

Description

+ +

cupsLangDefault() returns a language structure for the default +language. The default language is defined by the LANG environment +variable. If the specified language cannot be located then the POSIX (English) +locale is used. + +

Call cupsLangFree() to free any memory associated with the +language structure when you are done. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+language = cupsLangDefault();
+
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + +

cupsLangEncoding()

+ +

Usage

+ +
+char *
+cupsLangEncoding(cups_lang_t *language);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
languageThe language structure.
+ +

Returns

+ +

A pointer to the encoding string. + +

Description

+ +

cupsLangEncoding() returns the language encoding used for the +specified language, e.g. "iso-8859-1", "utf-8", etc. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *encoding;
+...
+
+language = cupsLangDefault();
+encoding = cupsLangEncoding(language);
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + +

cupsLangFlush()

+ +

Usage

+ +
+void
+cupsLangFlush(void);
+
+ +

Description

+ +

cupsLangFlush() frees all language structures that have been +allocated. + +

Example

+ +
+#include <cups/language.h>
+
+...
+
+cupsLangFlush();
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + +

cupsLangFree()

+ +

Usage

+ +
+void
+cupsLangFree(cups_lang_t *language);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
languageThe language structure to free.
+ +

Description

+ +

cupsLangFree() frees the specified language structure. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangGet(), +cupsLangString() + +

cupsLangGet()

+ +

Usage

+ +
+cups_lang_t *
+cupsLangGet(const char *name);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
nameThe name of the locale.
+ +

Returns

+ +

A pointer to a language structure. + +

Description

+ +

cupsLangGet() returns a language structure for the specified +locale. If the locale is not defined then the POSIX (English) locale is +substituted. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+
+...
+
+language = cupsLangGet("fr");
+
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangString() + +

cupsLangString()

+ +

Usage

+ +
+char *
+cupsLangString(cups_lang_t *language,
+               int         message);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
languageThe language to query.
messageThe message number.
+ +

Returns

+ +

A pointer to the message string or NULL if the message is +not defined. + +

Description

+ +

cupsLangString() returns a pointer to the specified message +string in the specified language. + +

Example

+ +
+#include <cups/language.h>
+
+cups_lang_t *language;
+char        *s;
+...
+
+language = cupsLangGet("fr");
+
+s = cupsLangString(language, CUPS_MSG_YES);
+
+...
+
+cupsLangFree(language);
+
+ +

See Also

+ +

+cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet() + +

cupsLastError()

+ +

Usage

+ +
+ipp_status_t
+cupsLastError(void);
+
+ +

Returns

+ +

An enumeration containing the last IPP error. + +

Description

+ +

cupsLastError() returns the last IPP error that occurred. +If no error occurred then it will return IPP_OK or +IPP_OK_CONFLICT. + +

Example

+ +
+#include <cups/cups.h>
+
+ipp_status_t status;
+
+...
+
+status = cupsLastError();
+
+ +

See Also

+ +

+cupsCancelJob(), +cupsPrintFile() + +

cupsMarkOptions()

+ +

Usage

+ +
+int
+cupsMarkOptions(ppd_file_t *ppd,
+                int num_options,
+                cups_option_t *options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
ppdThe PPD file to mark.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+ +

Returns

+ +

The number of conflicts found. + +

Description

+ +

cupsMarkOptions() marks options in the PPD file. It also +handles mapping of IPP option names and values to PPD option names. + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+ppd_file_t    *ppd;
+
+...
+
+cupsMarkOptions(ppd, num_options, options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + +

cupsParseOptions()

+ +

Usage

+ +
+int
+cupsParseOptions(const char *arg,
+                 int num_options,
+                 cups_option_t **options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
argThe string containing one or more options.
num_optionsThe number of options in the options array.
optionsA pointer to the options array pointer.
+ +

Returns

+ +

The new number of options in the array. + +

Description

+ +

cupsParseOptions() parses the specifies string for one +or more options of the form "name=value", "name", or "noname". It can +be called multiple times to combine the options from several strings. + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+num_options = 0;
+options     = (cups_option_t *)0;
+num_options = cupsParseOptions(argv[5], num_options, &options);
+
+ +

See Also

+ +

+cupsAddOption(), +cupsFreeOptions(), +cupsGetOption(), +cupsMarkOptions() + +

cupsPrintFile()

+ +

Usage

+ +
+int
+cupsPrintFile(const char *printer,
+              const char *filename,
+              const char *title,
+	      int num_options,
+	      cups_option_t *options);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
ArgumentDescription
printerThe printer or class to print to.
filenameThe file to print.
titleThe job title.
num_optionsThe number of options in the options array.
optionsA pointer to the options array.
+ +

Returns

+ +

The new job ID number or 0 on error. + +

Description

+ +

cupsPrintFile() sends a file to the specified printer or +class for printing. If the job cannot be printed the error code can be +found by calling cupsLastError(). + +

Example

+ +
+#include <cups/cups.h>
+
+int           num_options;
+cups_option_t *options;
+
+...
+
+cupsPrintFile("printer@hostname", "filename.ps", "Job Title", num_options,
+              options);
+
+ +

See Also

+ +

+cupsCancelJob(), +cupsLastError() + +

cupsRasterClose()

+ +

Usage

+ +
+void
+cupsRasterClose(cups_raster_t *ras);
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
rasThe raster stream to close.
+ +

Description

+ +

cupsRasterClose() closes the specified raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+cupsRasterClose(ras);
+
+ +

See Also

+ +

+cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + + +

cupsRasterOpen()

+ +

Usage

+ +
+cups_raster_t *
+cupsRasterOpen(int fd,
+               cups_mode_t mode);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
fdThe file descriptor to use.
modeThe mode to use; CUPS_RASTER_READ or + CUPS_RASTER_WRITE.
+ +

Returns

+ +

A pointer to a raster stream or NULL if there was an error. + +

Description

+ +

cupsRasterOpen() opens a raster stream for reading or writing. + +

Example

+ +
+#include <cups/raster.h>
+
+cups_raster_t *ras;
+
+...
+
+ras = cupsRasterOpen(0, CUPS_RASTER_READ);
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

cupsRasterReadHeader()

+ +

Usage

+ +
+unsigned
+cupsRasterReadHeader(cups_raster_t *ras,
+                     cups_page_header_t *header);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to read from.
headerA pointer to a page header structure to read into.
+ +

Returns

+ +

1 on success, 0 on EOF or error. + +

Description

+ +

cupsRasterReadHeader() reads a page header from the specified +raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

cupsRasterReadPixels()

+ +

Usage

+ +
+unsigned
+cupsRasterReadPixels(cups_raster_t *ras,
+                     unsigned char *pixels,
+		     unsigned length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to read from.
pixelsThe pointer to a pixel buffer.
lengthThe number of bytes of pixel data to read.
+ +

Returns

+ +

The number of bytes read or 0 on EOF or error. + +

Description

+ +

cupsRasterReadPixels() reads pixel data from the specified +raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+while (cupsRasterReadHeader(ras, &header))
+{
+  ...
+
+  for (line = 0; line < header.cupsHeight; line ++)
+  {
+    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
+
+    ...
+  }
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

cupsRasterWriteHeader()

+ +

Usage

+ +
+unsigned
+cupsRasterWriteHeader(cups_raster_t *ras,
+                      cups_page_header_t *header);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to write to.
headerA pointer to the page header to write.
+ +

Returns

+ +

1 on success, 0 on error. + +

Description

+ +

cupsRasterWriteHeader() writes the specified page header to +a raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWritePixels() + +

cupsRasterWritePixels()

+ +

Usage

+ +
+unsigned
+cupsRasterWritePixels(cups_raster_t *ras,
+                      unsigned char *pixels,
+		      unsigned length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + + + + + +
ArgumentDescription
rasThe raster stream to write to.
pixelsThe pixel data to write.
lengthThe number of bytes to write.
+ +

Returns

+ +

The number of bytes written. + +

Description

+ +

cupsRasterWritePixels() writes the specified pixel data to a +raster stream. + +

Example

+ +
+#include <cups/raster.h>
+
+int                  line;
+cups_raster_t        *ras;
+cups_raster_header_t header;
+unsigned char        pixels[8192];
+...
+
+cupsRasterWriteHeader(ras, &header);
+
+for (line = 0; line < header.cupsHeight; line ++)
+{
+  ...
+
+  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
+}
+
+ +

See Also

+ +

+cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader() + +

cupsServer()

+ +

Usage

+ +
+const char *
+cupsServer(void);
+
+ +

Returns

+ +

A pointer to the default server name. + +

Description

+ +

cupsServer() returns a pointer to the default server name. +The server name is stored in a static location and will be overwritten with +every call to cupsServer() + +

The default server is determined from the following locations: + +

    + +
  1. The CUPS_SERVER environment variable, + +
  2. The ServerName directive in the + cupsd.conf file, + +
  3. The default host, "localhost". + +
+ +

Example

+ +
+#include <cups/cups.h>
+
+const char *server;
+
+server = cupsServer();
+
+ +

See Also

+ +

+cupsGetPassword(), +cupsUser() + +

cupsTempFile()

+ +

Usage

+ +
+char *
+cupsTempFile(char *filename,
+             int length);
+
+ +

Arguments

+ +
+ + + + + + + + + + + + +
ArgumentDescription
filenameThe character string to hold the temporary filename.
lengthThe size of the filename string in bytes.
+ +

Returns

+ +

A pointer to filename. + +

Description

+ +

cupsTempFile() generates a temporary filename for the +/var/tmp directory or the directory specified by the +TMPDIR environment variable. + +

Example

+ +
+#include <cups/cups.h>
+
+char filename[256];
+
+cupsTempFile(filename, sizeof(filename));
+
+ +

cupsUser()

+ +

Usage

+ +
+const char *
+cupsUser(void);
+
+ +

Returns

+ +

A pointer to the current username or NULL if the user ID is +undefined. + +

Description

+ +

cupsUser() returns the name associated with the current +user ID as reported by the getuid() system call. + +

Example

+ +
+#include <cups/cups.h>
+
+const char *user;
+
+user = cupsUser();
+
+ +

See Also

+ +

+cupsGetPassword(), +cupsServer() + +

httpBlocking()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpCheck()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpClearFields()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpClose()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpConnect()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpDecode64()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpDelete()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpEncode64()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpError()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpFlush()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpGet()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpGets()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpGetDateString()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpGetDateTime()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpGetField()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpGetLength()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpHead()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpInitialize()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpOptions()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpPost()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpPrintf()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpPut()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpRead()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpReconnect()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpSeparate()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpSetField()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpTrace()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpUpdate()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

httpWrite()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddBoolean()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddBooleans()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddDate()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddInteger()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddIntegers()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddRange()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddRanges()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddResolution()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddResolutions()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddSeparator()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddString()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippAddStrings()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippDateToTime()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippDelete()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippFindAttribute()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippLength()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippNew()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippPort()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippRead()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippTimeToDate()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ippWrite()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdClose()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdConflicts()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

pddEmitFd()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdEmit()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdFindChoice()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdFindMarkedChoice()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdFindOption()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdIsMarked()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdMarkDefaults()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdMarkOption()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdOpenFd()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdOpenFile()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdOpen()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdPageLength()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdPageSize()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + +

ppdPageWidth()

+ +

Usage

+ +
+
+ +

Arguments

+ +
+ + + + + + + + +
ArgumentDescription
+ +

Returns

+ +

Description

+ +

Example

+ +
+
+ +

See Also

+ + + + diff --git a/doc/ssr.html b/doc/ssr.html new file mode 100644 index 0000000000..2d35390f58 --- /dev/null +++ b/doc/ssr.html @@ -0,0 +1,198 @@ + + + +CUPS Software Security Report + + + + + + + +

+

CUPS Software Security Report


+CUPS-SSR-1.1
+Easy Software Products
+Copyright 1997-2000, All Rights Reserved
+
+
+

Table of Contents

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

1 Scope

+

1.1 Identification

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

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 5.50) and an image file RIP that +is 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.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

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

+
    +
  • Adobe PostScript Printer Description File Format Specification, + Version 4.3.
  • +
  • Adobe PostScript Language Reference, Third Edition.
  • +
  • IPP: Job and Printer Set Operations
  • +
  • IPP/1.1: Encoding and Transport
  • +
  • IPP/1.1: Implementers Guide
  • +
  • IPP/1.1: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
  • RFC 2567, Design Goals for an Internet Printing Protocol
  • +
  • RFC 2568, Rationale for the Structure of the Model and Protocol + for the Internet Printing Protocol
  • +
  • RFC 2569, Mapping between LPD and IPP Protocols
  • +
  • RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1
  • +
  • RFC 2617, HTTP Authentication: Basic and Digest Access + Authentication
  • +
+

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

+

There are two known security vulnerabilities with local access:

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

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

    +
  3. Device URIs are passed to backend filters in argv[0] and in an +environment variable. Since device URIs can contain usernames and +passwords it may be possible for a local user to gain access to a +remote resource.
  4. +

    We recommend that any password-protected accounts used for remote +printing have limited access priviledges so that the possible damages +can be minimized.

    +

    The device URI is "sanitized" (the username and password are + removed) when sent to an IPP client so that a remote user cannot +exploit this vulnerability.

    +
+

4 Remote Access Risks

+

Remote access risks are those that can be exploited without a local +user account and/or from a remote system. This section does not address +issues related to network or firewall security.

+

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

    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.

    +
  3. Repeatedly opening and closing connections to the server as fast + as possible.
  4. +

    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.

    +
  5. Flooding the network with broadcast packets on port 631.
  6. +

    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.

    +
  7. Sending partial IPP requests; specifically, sending part of an + attribute value and then stopping transmission.
  8. +

    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.

    +
  9. Sending large/long print jobs to printers, preventing other users + from printing.
  10. +

    There are limited facilities for protecting against large print + jobs (the MaxRequestSize attribute), however this will + not protect printers from malicious users and print files that + generate hundreds or thousands of pages. In general, we recommend + restricting printer access to known hosts or networks, and adding + user-level access control as needed for expensive printers.

    +
+

4.2 Security Breaches

+

The current CUPS server 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.

+ + diff --git a/doc/ssr.pdf b/doc/ssr.pdf new file mode 100644 index 0000000000..be349e6ca1 Binary files /dev/null and b/doc/ssr.pdf differ diff --git a/doc/ssr.shtml b/doc/ssr.shtml new file mode 100644 index 0000000000..6a378c1ee5 --- /dev/null +++ b/doc/ssr.shtml @@ -0,0 +1,150 @@ + + + + + + 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.1.

+ + + +

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

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

+ +

There are two known security vulnerabilities with local access: + +

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

  2. Device URIs are passed to backend filters in argv[0] and in + an environment variable. Since device URIs can contain + usernames and passwords it may be possible for a local user to + gain access to a remote resource. + +

    We recommend that any password-protected accounts used for + remote printing have limited access priviledges so that the + possible damages can be minimized. + +

    The device URI is "sanitized" (the username and password are + removed) when sent to an IPP client so that a remote user + cannot exploit this vulnerability. + +

+ +

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. + + + + + diff --git a/doc/stp.html b/doc/stp.html new file mode 100644 index 0000000000..18c8718cc9 --- /dev/null +++ b/doc/stp.html @@ -0,0 +1,168 @@ + + + +DRAFT - CUPS Software Test Plan + + + + + + + +


+

DRAFT - CUPS Software Test Plan


+CUPS-STP-1.1
+Easy Software Products
+Copyright 1997-2000, 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.1. +

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 5.50) and an image file RIP that +is 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.1: CUPS Configuration Management Plan
  • +
  • CUPS-IDD-1.1: CUPS System Interface Design Description
  • +
  • CUPS-SAM-1.1.x: CUPS Software Administrators Manual
  • +
  • CUPS-SDD-1.1: CUPS Software Design Description
  • +
  • CUPS-SPM-1.1: CUPS Software Programming Manual
  • +
  • CUPS-SSR-1.1: CUPS Software Security Report
  • +
  • CUPS-STP-1.1: CUPS Software Test Plan
  • +
  • CUPS-SUM-1.1.x: CUPS Software Users Manual
  • +
  • CUPS-SVD-1.1.x: CUPS Software Version Description
  • +
+

2.2 Other Documents

+

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

+
    +
  • Adobe PostScript Printer Description File Format Specification, + Version 4.3.
  • +
  • Adobe PostScript Language Reference, Third Edition.
  • +
  • IPP: Job and Printer Set Operations
  • +
  • IPP/1.1: Encoding and Transport
  • +
  • IPP/1.1: Implementers Guide
  • +
  • IPP/1.1: Model and Semantics
  • +
  • RFC 1179, Line Printer Daemon Protocol
  • +
  • RFC 2567, Design Goals for an Internet Printing Protocol
  • +
  • RFC 2568, Rationale for the Structure of the Model and Protocol + for the Internet Printing Protocol
  • +
  • RFC 2569, Mapping between LPD and IPP Protocols
  • +
  • RFC 2616, Hypertext Transfer Protocol -- HTTP/1.1
  • +
  • RFC 2617, HTTP Authentication: Basic and Digest Access + Authentication
  • +
+

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..7c0c262975 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..339ccb2670 --- /dev/null +++ b/doc/stp.shtml @@ -0,0 +1,47 @@ + + + + + + + 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.1. + + + +

Document Overview

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

Local Tests

+ + + + +

Remote Tests

+ + + + + + + + diff --git a/doc/sum.html b/doc/sum.html new file mode 100644 index 0000000000..ba9adb94e9 --- /dev/null +++ b/doc/sum.html @@ -0,0 +1,540 @@ + + + +CUPS Software Users Manual + + + + + + + +

+

CUPS Software Users Manual


+CUPS-SUM-1.1
+Easy Software Products
+Copyright 1997-2000, 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.1. +

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 5.50) and an image file RIP that +is 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-edge" and "-o +sides=two-sided-long-edge" 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-edge filename ENTER
    +% lp -o sides=two-sided-long-edge 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
    +
    +
+

N-Up Printing

+

The "-o number-up=value" option selects N-Up printing. N-Up +printing places multiple document pages on a single printed page. CUPS +supports 1-Up, 2-Up, and 4-Up formats:

+
    +
    +% lp -o number-up=1 filename ENTER
    +% lp -o number-up=2 filename ENTER
    +% lp -o number-up=4 filename ENTER
    +
    +
+

The default format is 1-Up.

+

Setting the Brightness

+

You can control the overall brightness of the printed output using +the "-o brightness=percent" option:

+
    +
    +% 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. The default gamma is 2200 which matches the +sRGB specification.

+

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..c4a33c791a --- /dev/null +++ b/doc/sum.pdf @@ -0,0 +1,635 @@ +%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[11 0 R +]endobj +13 0 obj<>endobj +14 0 obj[13 0 R +]endobj +15 0 obj<>endobj +16 0 obj<>endobj +17 0 obj[16 0 R +]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[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 +]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<>stream +xÚìÏsë8rÇIŠºÌ‰öŒî´üt§çyšÝ­ÚJñÙfvçÖ$ÁÊ!•S*Ç6•üÿ±~X"H€èn$è5¦jêÙE|ˆÆ·@ƒúÇOßòýÛßò?=å¿ýžÿçÿô,~*ÅOÿÈÛÿù×?þøÛï¿ÿºÏÿü—_Ÿò§§§·kýñõ¥ù÷¯|­ÿöœþº?•ßNå÷SùË©¼œÊ¿žÊ¿üÇ×?òÿýŸÿû¯¯ÿ–ÿíÛ׿ç‡oß¾>ÃKþ=ÿãõ§öcøä²+âõi»Ý>ÜËÛ?¶ß_—Î%^¶wY¤*w÷¯ËäOj¤Üöû¸ē‰é½Ü?–KáÂC]о/ëå!"—x[ÎõœE¼r˜ë‰KåÒ!˜¾rÛg޹^òȾü\ÆÕÊÏ3s=GžJRÎÉõ-òVâÃl\ŽuЄõV¾ÌÂ%²( + ‚B¹ü29×$X,0X –€Åƒ %ƒ/° ¬(ÚMÄåÝoÙ9h6×ÄXo`å\ûhò’LÀõ#𡬼sÕÑ,åÏ\M6A!|…gi,A +Ú Ñ ê£s5Ѭåà‹+›— 9Ä`™ãÅ`ž‹,öD.1?V{àÊàŠRç\uD98æY\‰c®}HÙ8媣`Jé++D91WT蚐°ŒÒË TÔ  LÔ‹Š4ðZåªBÃ2t,OãQ ÔxŒsÆq‰±FãzX¢Æ#F,Ï%£FL×]w÷Ûí—×cy>|ðÛa0IwÅ÷_†ƒüxÂ[‡ÿîŠG’þÅ˃ŸßÝuoœ*=[ í,¸ö~ºªÛk[ça=xì.Bú±àæØ\ìPƒ–.Î$[q¹¸¡==·aMJ&³»XéԜ.K™\¬@ž› É貘ÇUùÑv‡]¶cqeSÙà՛eN¤ܯjؤ½s’  ®|²¡ÅϼJé\Í Xd°˜ÎEùØÍÉÜZ9ƹfÂ"‚­¨\Õ FÈ1ŒȕυEÛи'’ –Y¹0p7ñú¥uZj+Cg‘¼c,Òé« …«rÎX•½ÅÍÁ‘jÄ¥{.B J<—°ÒlKÃ7D=Ì:¸ÎåÛÁÉ %i=•œkˆàBf½ .Ú`Ø`¹Š¹2O”,Á W­Ç’ó ìÍПR4q‡ãÚa…„–¤8®´&1Š«žÙ#3ì€á«aÚz/8 [c¸²0Dƒ¢õ ‚«æfóuXiæ*B J‡íÌ\Y OjOjäªÃê.d‡%F®"°îBú°ÒĕÖ]È'½1p5Á¸dZ“RW\wá¢ÄÄÀ•6ºÐRVŽr‰» 7æw£\u€Ý…[FJG¹*OŠ…²¢d”+ (2$*ÇVå'ÆB ÃRåÓ©¹Z’ Wå“s! q5ÂÀÚÛ=W¢È£­ÔrAˆ"v@;-W¨jàLi­ã¡ªnè¯t\5-4”=Ùí§ž±¿ÿ.Ï´’T¹Æúù=¾aÀ +¢6(®–KH·Kh%ºÖRÕÓbQ®•–ër›®Îa‡Àà ¯Çé¹ £^ >ÜÌіœáµCrí´\MçùÖ 1£$UsÑys¥Z®³í%·NH)}¢æÊ‰Îkœ+ÑsÝ´BPf=ègŒàp‡åz7.×MÛk¼b”¾Tq5ÔÊÀµÑrÝD° ¬•T؇ô¹WŠçZ鹊÷G”Q&ß V<זByW¤çª/ŸÕPÌ1PRWF4C#×NËu¾×úü+ü’QØV +.A5C#WªçڟòáªÕr[¬àª©fhäŠõ\盽§5Rì•K,×êZ[Éu6Ž;êÊ12BªWNZ,×:{—'%WG¤(³ÔgO@• ž«x j®Š5K5†ˆëWC6Ãq®ZÂp ÖbI…Ó5 ÊFÒâ¹Ä»Y¨¹®&EZ,ip-â\9%pžê¹*֚Nè(; +\n£á¬5;c+\ŒôÅq®æ" +®K‰kvª‰@“¤¥pµ¥×qgéB™ÐdcMãº(½Ž«àôWòD@“ë¢ô:®Œ3¾êÙwCÅuQz WÍÛÃÈ0’ ¤h#!r]”^ÃUðûMÏ%s Æð2r•^Õñ6g +ÌÃ’lì¨\g¥Ws5Ì]Œ +㘁´¶ÑR¹ÎJ¯æ½ØER2WÁ^f®“Ò«¹rfæŽÀ8f DQ)ëd݅~^¹e¢IàkSYŽ­\§Öç*®³Ý Fȑ#š ”(ªT?º²k ±ÌukDŸ+?krN7Ä="àVÌµë>š>h¸Þ;а›‚]†Yw¹k6+IlºŠšô¸ Wuáiè†X!dr¸Ñ˜ÄjøCýsȵèÝJ´§•¸rŽlH[âã‹:\…’K\[°'¢@Ø¢C­I¤€]Ÿ«VrU×Ê=öEèà£ÃDïû¯´ùÖṌŸêsí¯#èùVž«áxåÛ-â;^WÈ\OÌɱonn0¾d=äª\ÝT”‚lˆ{ó€¼0ÚT¹WWojò$ ð\{–l lbÕ¹.¶*qeÝKž„‰×ñÒáÊY²Ñ˜×Ó{Šyq—KΈÚ{ÈhzªX¯üPy8Å:F—« »òúh9ÔNþnï5ùÒ*¹Ä€+“,¯ñª è¨Wo'ÍéŧñýGH©\SßËy°†ÇeŽæãvQ°2Ÿ,’+çEQÁse¼(*t.a#‡s5–r*W͍çª>š^¸ +vt6מ͕4™¿peM/\œ¥ùp‰'óg®úÃÉ<–k2ߝÎ-‡͋ó·•Ü:\[æ»uîªßFwÒ²ßmµwpœOm›.Ò,²Î-ï\·u›þà,•\×FÍÕI¿\¹r¶ûRãkT§×ćk¥äjÔûËÛ}©4fÜkbÄኔ\¹z߁¿h£¶W]nj¯‰;×NÁU UPn9Ár­4áËNŕr¸RW6|ŒŽ¹Î«Ëë51áp%C®wшﲫÝÊ-§h®š+Vqõó¡¸g¯r~ô'/ÙÅlp\ëQ®Ó¿^òHjÁZv,¥Šk£tEr<Џ¨ëdÞ7ÛnlÌ\—᯻?"éx@·‰+×à¢Zr—Ûj{‡àꤥÈ]|Ëíé71âp .’7.y<€ +£®[‘"K~­lâŽÃÕ¿(—óM +-áðì8—Ðpz®”ÃÕ¿¨7RNf™*Œj1\·Ùÿj®˜ÃÕ»¨ðTà¹b\Šã|f.ÅEußÁnßÊ#`ÂÃĞk¨Šã|f.ÝÀT5_ŽÜp ×^­óŠã|®áE…ÒÁ&ŒJ[=Ì®9·r‡Çù\Ër¥#Bq­Q\µÚ՚8JqœÁ5¼HËU;â*”ñÆË- é5qxœÁ5¼(S:"×Ã%¢"ÎSÇù0\ƒ‹´\?Œê´áò;ô¼RqœÃ5¸¨[ývGסµœm”MçÃp .Òr?ŒjÕ£YU4ñ"Ú4®þE\-š+Uý6.5MìçCqõ/Òr¹ê^,ÕMìçCqõ/Òríùáa«68Íòþ ‰ýã|(®þEY/Mõʕ;ãŠK W'T•šØ;·ãê]ÄçJ\ñ®óۋ_¾,{lÔMìçÃqõ.Ê;Š-qen¸:ù‡Ýxã¼ì‘ª›Ø;·ãê]4ˆ£*,WÚâæ)­Š«ó~(EO¢Må’/Ú÷#¢âÂùåªÇ¸äã|H.ÅÀn÷X®µW£‹ç¯AeNä’/ªúC%;s Ï\BsŠCqœÉ%_T÷$[DX®W;Ê.é"Ñ Í« ¸—|Q&°üÂeÎ=Üy䒎óa¹ä‹ +E2þW=/WÁá’.ªn»Ê·EÞÙ¹j—t‘è¶²¾Æ6ÓJ\‚Ã%_”ßö¿ž#W铫{œÍ%_T ö+Càª8\òE½H0?qÙL—Q\Ù8WÃá’/’gÆé>®Îq>ès¥”ºór=ŸÞa?bšK©;3×Cÿøšü²¡ÎæuÕ»ꝪHqPJÛ:k®|¾!çéw·§†u\y1Ô׏áŒF~™WsÛìø9QeäÚÉÔ—Pì(É/4¬®KüuòÈȵ™‚ TSë¼;Àz齺 ®u+ M?\™j« ºã “Òdúu\©l)^¸š÷§»nÝî«ko»õʺ ®Dºµ®êºQ(¾unڑÀ[v…².Ÿ«öÉUtv¬÷7ïÒqY·äsM]Õ2¿ú®òöNå“+ª›v^Ȭ©K㊯ۧoƒ8ñƕu—áòžÒߌ§©KãJ®£0qÙÄóҟá¦×VËIÚªº$®Õõq¼=™t®êöÓ5ä$mU]WÚ}tk;.CúáõÏÍÝ[ÙtĪ윑Ò×%qÏ]ÓÆ+W¢ûѧ“T<¶ÔçÊ/ƒô8„wÞ¸2]:ÎeO¹éÀd#©;x®ýåóŽŸ|ðÆuŽš¸1‘†‘¶.‰«¸ÈÐÑÒKo\—½Îûƒ:À:eR¼Ë¹¶.‰ nÙ¯qëë¢Z{þ⇬ã‹õu•\ÃÄÎEu¯G÷叫“Òkmñîm®¾X_—ÂU_ `ü`;®±}½n=é½ÄÕ0‹V[—ÂÕ\~<ºeK®±}ØByŽCš—ƺ.]_ˆ¾ç²Ú_ÚÌÒ|Õ¢¯Kàj/Žùô[\½,Ú¸ôdЍKá:;æ“[öÉÕyіL¡ú’9]] +×Ù1×'ï“ëý ì —J•l:ZÇuvÌõ©¾—1ïë9Sš\ùPÔuñ~ùäËãÿc—‹|¶—‡á¤¦ÒLrTu \ÕÉOnÙ?×­µ«^(u@Õ%póÉ-OÁõ. +‰vЌÕ%póÉ-[raß-Z‹ÁX]—x÷b멸n‰×f®^]×Ù1ŸEr”Ë&ûø*™ìе\cu)\o&˜4·õS/\²{ãb§®.…ëM2âúì-¹JÜú¡k¬.…ëØÓUt}Q7®D²­x”KW—Âçð±‰ËæÜM.ý9Õù±º®ê|²&±çڍO¿6ÝyÈJË5V—ÂUߜº7®ªÛŸûÞmz«Kájn³Q.›sˆçkãï·M­–k¬®!ž—Þ¶%ä]A ®qö¶ ©Ÿ,ŽÕ¥puÞ ë«™«õ¹F꒸r—Õ¹ìf¤jŸk¤.ƒ«´çZãÒmú¡ÿ VÑ×%qƒßxàjô +3àj¸ëQ2\ŸÊ(—Õû7䵘_ÚQ.}]—îý¬n¹:}l \Úº$®úêÓǹ¬²Þè!Ón”ØÔµ*–ïí¹Ê×ëMóU|–ïY +¶X¾ë“kz.ó떗ÉUüÓr•‹ä2/pÉe3aþ䚞Ëjb¹h®õ"¹Ä?-WºH.ólõA¹’ere0ðµü>ŽO®¸ö0ðÅ}Ïn‘\ðA¹ª Z~¯Ù\Åô²×å÷ÐÍULMÞá¾70¸@ªrÃ\ e’ºÒò{9ç*Š+[\Àa +%°ß{ZÀ‘›ì ù=Å¡­´e&=@~¯thG„â‚¥Âèo‘ßoXÀQã¸÷}ô•±mç˜Á8lc®Á9æ½Qæ#/Á9°Üè–ã‚s`™±Åš3‡}€²×ÀXcV@éK`3Ëڬހò9°ÊÜX@=€ÀXa6.@l`3°½9êT˜ËÍ"8á Kèmœ£ Jè„m®gƒú¡€S˜ „A:àª%ô¢©€ìڐ„>G˜ ‡bH}fv_ï\bAB/0Ò -Vè׋‘Ã]‡+_Ž V˜Ȑ+ A,0 +-V裥ÈaÜ媗#ˆ(Â-ôDˆ *âƒ-ôéBäpÝåB} Â(»‚-ôÇ¥€VÏP„#C̾:\ÕB")£œ· Å }ºÙHd.„Ð'‹TæB,Ýċu+_†pd8üƒ"âȇxà B8j¤—Â!Gl#´A `1Û¨«>BðÌØå +h)‚¸xí\Åú,(ÖCéÑg­¡% ÇÜ ýŽhIÂ1ó3?ú•‚+~€áï€d¼s°=z @KŽy>r’s˜y€Õø©bå™a÷H*:sˆH؇–(30Ê&ÐúyÖ9eˆιÈQDs‘ƒ²Ôā9£Ò7”AОQéI+Ò@½t>¥Ï)Mª’ζÚ&HšÔ¡9›!"li¥åڇkˆ´åhél¨vc! »ô™ ±¢g83âžö¼nų¢ †®@žâÌcˆñqCË`3Ĉ9qx@Ë`iˆf(Í4€ó`¦Ÿ¬Tԇ -g€M>kΩj-k€MœdY“½´¬6± +ÈcX]>±rz‹€5D'VFÔ +œéöÔ1GNÀY™8樼A:©ÔgB©œÇ Üϙ.H,8ޏÃtºc wàÊêd†kÍÁ…Tú‰:,c=càÔ4Æ €?R§é°ŒÖÛNÓaә_‚& :C¢Åqí±`»0ºk…äªé0‘qƒph­ ±÷UKó„ªY.´v†èuâ,øV­!zÕzìÓÝ ¹ð†èQ:j ›ÖÖãrfWŠØ ¬OKüñÍPË%¢¹-±±’.h­ ѓ&æV>¬­'BõÊXZ?Þ¹±´°öõ^†˜È,e \<1÷3–½í#×½{&ܸ¥rU¤s©ÍJÉ\"š LdöܹK0‘;¸)82‡i\o\´;¼•Ÿ'–‘P¬.t¬Â^¿¹1p1_uFÃÒÇàd}¡ãNSbé¥ +\EiW°/)áøf08Ô&[õ cœFwžÿf<[l2êR6W›qÀúßtŽ*OôÛø\‹+Š¿S;‹añcq€‰‹ÙaQt_zî¬ñ¹‘‘«ˆ¸ÿ¥ó/9k·6\"â—{”56¼OßYqYtØqœ=šÌñ…Ie˜>˜¹l:ìŒöªÿ짌ý¹K.ê4Li¯ƒ~/ÛÌæqµ¶\Mä¦ÜÝo·Û/¯oåe»}È,?mcÍå¢ÃœSþ#†KȵqÀe'‰³tŽ+¼Û9á +®ÃÌK_8.±´îBrvm¦(ˆ=$W›…ÄupÇU/«»Ð\¬•O_ºäj‚áÚ´.¹‚ÑzÜöžKdKÑxw gÑ q!Øý^ +—XŒÒ¸°DôÖ!‰kvKÄgиš…X!•kæø—°MäšÕ)¹/T®9½3eû‰Ê5c`OJš#sÍ6Ähi/t®™†1±ŒÁ5Ï#îí2¸fbÔ,%=pÍ`sM®ôT9×ÄÚÁÈdr‰<\)´ášRY©Ã\®éÀx™dl.FÚÏ$ŽËšk¢Éóā×þ9椰áòoŠü,M+.ß`ɧv\~UÑ&Yؒ˧ƒ¶Ê¶åòf—ŒoÍEΡö41qÏåcÚb™®î†Ë½,ڟ›pÂÕ +·¶øhß"7\o¶è®Ë’CW+Âé,—\ŽºìþІÆÕŠ'küâª-.¹ø©ÕªGw-qËe‘^Hݞ“‹Kæ–ʇìþ‹ë6øà"æÅÇ[ï¹ðÃõV^qÙññýw/·÷Æuê5ƒAÞm_}ÝÛ'ש۞¶wê~z|õy_ß\çŽ;žpØ>ÜËývûøúêý–“pÍPàÿÿÿârõä +äÿÿMŽË‚0D÷|Å]jbko!h—jpG‚P> ‘â#5-hø{[Ñíœ9“ÙÊd¹ÀȐq* t ²›íÚªÆöÃS9 ­×ÎC©n£2sy Vˆ ƒ@0¥ü«‘¦- RŒÅæ9Í".”Ÿ~«•³Ýxü»˜¥4ÿÛ±÷É]NçPˆጱlŒ:†j=tÕB&‡äN=îèendstream +endobj +102 0 obj +6275 +endobj +103 0 obj<>>>endobj +104 0 obj<>stream +xÚ+ä2T0BCc3JÎår +ár á +äHÉHendstream +endobj +105 0 obj +31 +endobj +106 0 obj<>>>/Annots 12 0 R>>endobj +107 0 obj<>stream +xڍUËnÛ0¼û+=9@¥Jò»·æ }¨±Sôà -Q¶JTIʆûõ’2ì¼Ð"€‰ÃÝÙÙÙõï^Lþbš$4SVõ.—½·3J"Z4Œ‡á„Æ“!-ó~ªxÁ2~±üĐâØ" É$L,j¹-5iY˜=SœZ͕¦ŠÕ-”s©rÍ5m垌´§d¶œ®dUɚ¾ÎRªÊڔõ†mxE«þ»«‡tñnuA?«.ãг˜Q<±," +’(t,»kßv\íJ¾ÊÖâÆ·üGÞFÉ] ÆÄ¨‘ʰµàøÖa;pE…Tîî*I6\1w¨]ÒÜЖiËàfًÂJÛGl÷w4A±Ï)UG3ðòo‚¶ ^ÇxÙ5ç5äÛq49­ôfÔó@;ŠñÿöüøYžÑxzEmŽÄ;n7LhqlxªdÞfÆU}ºu7û¶ëP¶’†CXmX3•Ÿ„ÕR´ÆöØj˄ð½Ùñ:—ðÐ6nàñÀ;Îy,$ë’S׬­ºNþ°÷蒫G.ø24Q֜–+ëjíuæ¡}¨¹ÅÕܜl‚BÌ¤€Aç7ËÛ`ž¦°(óð5Ә[R±Å»é—\»2èwË[$%ذK|,ç³ååÒÀb׌[‡®úŸÓë÷t{ǓÙêâ=-`oœáZ³ §K!³GÀ_.í©Íð©iøÎMG™Ñ!&´|–R·õ8œµ/͖G ñR´uf›ÁDi¯êÃò\dÙKõè+§µ’{mK¶,R©ÍSߘSMn 4®Í˜î4½ÆpŒŸAºs¨ùWÄFA^‘kQfÌ_hëœû±|1ªG×3ÑúÙÎZmdUþAî]·^dAw_èn{¢¾êg­R¼6â@ž¨,^¢Fá(Z]<ãkE`5••mSQb‹ÜÏS˜„‚EZ 3q¬ª–up&Y'©~¹î†‘Ÿ¾k™µˆýÏÂ{s1ã@ª « È(‰ )„Ü»©äÎú£žuÁ“©ÃcüU2žÐÓìý˜‚‹õ)ÑìDô¨Øk‡œ©,³g!=vzüEò´C/ÐÙ¯Öp…3dÂ׸۟ß{vÙ !endstream +endobj +108 0 obj +847 +endobj +109 0 obj<>>>>>endobj +110 0 obj<>stream +xÚu±nÂ0EwÅÃ7vL0+ˆn¨A1tébÅǨ¿_ÂX½·¼«sôn„¡ˆÃPViͅ,y{7` ª—”£’‚J¨6ûâÕ uŠ€¬DŽ&h×jߢö½ Öãã'ôW7<ї«@ÎʨûG$¢hy´æÜ»ÂÑ&k¸Øõúq~Úý³!ÇŒ–’Ф\në͵ ¿Ú[l묵»ëïÔÊY5§Sä3^$˜§Lˆ9MßÇ»ö¶ÓƦt¥È†ü€×H¾endstream +endobj +111 0 obj +200 +endobj +112 0 obj<>>>>>endobj +113 0 obj<>stream +xڝUMÛ6½ûWÌqð*þŠw÷Ø ÚC².֛ô°ZÙìR¤JRrüïû†’?"-P0,™3ï͛7ÿGSšà3¥û͗”W£ëÑ»O4›ÐºÄ÷2›Óò~AëâfJw´òÚFm·ô|‘+zjÙ·š÷·ë¿¶ éTÂ»ùì>›Ièz§å;UGöT{×ê‚)K®'WÒÎí)î˜>ºªr–^¾üþçÞÞù·uh4½´ Ý-&ÙC‡Ã琕wÃՏÔpx¶ÌR=Ÿœ§+¨;²ìÜ‰ú˜¥þY–Ú©@µQۆ‹Äôuö~™Ñ‹5úé³Î½ ®Œò–¾i[¸}H¿ùYåOÏã®>>>>>endobj +116 0 obj<>stream +xڍWÑRÛ8}ç+î#ÌC(ÚÇ¥”-:›mÜÙ^[&jdɕd¼é×÷\Évˆ 2%ޤ«{Ï9÷\óýhNçø7§7 þ)ê£ëüèìöͯ(¯°²¸ºÊ”—ÇùFR.‹±Ú>îNòoØvIóyÚ6»Xd—¼íý×劔§µð²¤¶±†„!YK÷¨Ì#ݙ ‘|¦®¤BháÇÅ¥S&ðö¥³ÁVŸ’ut·\fümâKi8 \=“]ðÕ²^;Q ÖzG¥ý!'[Qñ¤CåøÙK÷„_µ0m%ŠÐ:éüiÜÑ)­›|Û4օŒs3ò¿@ŸUᬷU˜Üü¯2¥íp]#ˆ‰û²Îú}8œ|)+e¤'±‡ é«¤ +U6Cí(²“È¿‘¨ˆðÅEúf×þ ÛeQ®V[Iµ,•˜$èÕyJNz«[ޚŠõ–o ›Œîù ˆ¼³ÄܐpᬠXZ^Җ9Û1%–a< .ØÉÕ}Žž6­),=Ÿ Ûz¤ª•f<:±Ë諉5XÄtÏsØØN⮔ŒÐȼg‹Bz?¹µ°&8֍h +€b_·4…Û5é¹[VR·Å†jë@¿, Š=nH@X]2è`ñ%‚!~-v¥° ×È}ÜA³œ…”;a<§¨ðy¾<¥n£Âð!°¡"J\÷ºÅãTúÏ)È(ßà(bIò +X䖞”ìÐE[‘ˆG’>·ž”êô5¯ìÕ56LëƯW+³[;\(Ý“è òI•Qö…­-ƒd*ÏæÙù(¸ëØ:ŒtØ» ń̘|ik¡°›¤5 +9ɃzAdt£¥/…ÊïWϤ1ZxJ‹µ–@ˆª–Ý‚˜…Øq¶šÜËÕfÉ÷&:»<ÏÞòê'tî«ÖùA€ö +͐j‡¾]×*° 8Vz×”¢-úhǰ†ÃøÇ}Šv¬$T*¹š Ö¨ï-¬­­×lŠA¸d<ó€L*ãÂ{õhØ®- „­®æq6aùpÜú6:Ĩ¡‡“> ö‘ؾñ$GßBX[(Á…v*lX´õÔÁ¸7Ù +ÙÝ(ùYŸ8š£°’½…ãJëTؽÎÂ{ ¥ÿý ýÍ©ezºiô³­±á”&/Ehð` ·EZÀm‡1På~­”óÓ³WáЖÊÄÍ1ÎëµÞ*ÍÙ¾Zk¿žì‚5áSNj¦ÑCs ­4x0‡0 ac‰*ú6fÛ@°5'HVg/Q=NmV¥%j^N5!žÝ_C_„gBîâ7lߖßϐ䗻%>D*ڟ†grqª³´V¡M/†þf¯O—nþ_Э½ìâûl‘ÝY§á +MÑJLã;fugÝcYÄçO2Ü(…Mò8þ³iV÷…‡“SZ¥–ù X¡k¼ŽmSä{¼X¦ÎÃú5”:¾Cõñ¶Wâ|ñ.ûƒ—çci+¼×v܈_=kâ3^Ž…æC³´wvu7_òw—ço3þÓáÅ? >äGÿýŽUUendstream +endobj +117 0 obj +1356 +endobj +118 0 obj<>>>>>endobj +119 0 obj<>stream +xڅUÁrÓ0½ç+–\hg7NÓ¤½1¥0ÀS¦épéE•åXT–Œ$×Íß³+ÉnêÂ09$–w÷í¾÷Vù=ÉaŸ6K8]¯'—ÛÉÉÇ È7°-ñÍz³ÉÖ°-Ž®­Ô^X¸²òQXw¼ý…q+Èó7_®³Õa\ã@jx{}Üh'S‚Ñ‚¾jc”Ry +sà²”¼M,’ÅT©¹j áð…cu£Dÿžš@èü4[t„„ÒXø$:%¼Ÿ_3þÀl_™ö‹ðÀtWÂ=ÐïTÅeð³’XÕWÒ¥¾¡0ˆ§‡ÐÂ27^ÖLi}Óú4a²,…z(ŒB¹Hë¢F|(W™ö¦Î4tVâ >Y0Ò{ +©gäÀØÆPêÚW¢Æ×È‘•Eažœ¯Ù9Å}¾3öAêÝÿ´‹ˆ\1ç°i£‘ÊpÞíG8†Ê±Ö›šy‰Çj®Â³:é+0oS萯#|[dy4V0 tàNø¶ &Ihx(yáÐcë’j}_î '%Q×£q´ …p£ЍÔchíð9<⌒ÚÇé‚c9o-Ê˃yŸap>ÖO7£<š—=›€¾Gº8È'õœ$8À—ÍÆjŒRہ…t'Ü!i¦Ž%Q挸@åê‡tB îC@Ÿx¿O+¶ÞU’W=]È1±zw$²]ӔÿŽÈ˧D拣å4»;Nåz…eʑjæQÒâFÇ­“ãŽ$.±ä¸Éc/ y4ƒØ¹ŒE³HÜ¢½9pè 6ӛô5!ÙhH²üÍhu«¼¤K%à 1ˆ,QÈP²©öެÞ+Ýw2 ŽOá^š3Aü6áá0ú­+)]CNPƒÍ©P¨Š§\ +Î{6 6M:x+Ž?n’0ÒýՀ´9‡DâL¤<Ö·{`÷xÁaoÓÔ\`ƒ¨/™T­ShµB'—öæ°Ø¼Ç܅ûo·7Qìó$v¾¾ÈÎàt‘þe‚wnLé;ÿ6XúÓ- ;ÑóÍrñ¿¤Õù"»€ðöŒž?l'?&,òLºendstream +endobj +120 0 obj +815 +endobj +121 0 obj<>>>>>endobj +122 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS04³Ô3U072PIÑp VÎO+)O,JU-N-*VðMÌ+MÌÑ Éâ҅¨Õ…*6‰™šé™+€ùE™y%©E +.E™e@ Y×®@. ²!Õendstream +endobj +123 0 obj +116 +endobj +124 0 obj<>>>>>endobj +125 0 obj<>stream +xڍTMoÛ0 ½çWp‡)x±›&͎-ÚۆnqwêE±éZ­,¹’œÀÿ~¤d÷#]‡"@I|äããcž&),è“Â:ƒÓÍä"Ÿ|»Þ@¶€¼¢ïe’Âj½„¼œf0‡['õ=øáÆJíù°íÇæ$ ÜҔqóœŸfë$cl^KE-Z\mzÓýoÀu»FúQ˜O§K½g™€Äê_ù‚);0UÈèèÁbáyJêBu%+|cœßV¶> J6âc8iÎ6J‘?fqü8‘Êš†2:2I”W´­’…ðÒhªNgÆ0 s®¤ÆjYÔ¸çobAïzZñ/úø²6&,ˆîEû¡y°qôR©8âÆXrO-4ÏùÙb/¤»cu-+€î9Èñ©/ˆ{9Äi£L!Ôè¹½Dµ–d¤&1(¯¤÷ÖXZqóº²a1¸¶F0ö1 Ñ +8¤ê $©ES}Ž gÌ;äx·fä´iãD7ž¿h¸>>>/Annots 14 0 R>>endobj +128 0 obj<>stream +xڝVÛnã6}÷W ²(+U’eË)‡®‘mº­wíýZ¢-¥©’T ÿ}g(Qõ%¾´HàDòÌè̙3Gü{C„?1Œ§ô›×£O«ÑOŸ#x‚Õ†îLgY˜ÀªxüDc,³4ðòÇêåۏ«W N!Ž):À𠙆)…¯JA󪱕’`žW›Š°%Ù«vLZ° + çÀ@TƂÚ@£+i¹6Éƒ©L1”ѼQÚw?oµæXÂìå5a‰ ˆÇ܂oX+¬/JC.˜1a7àT]aeîÓ>Bkø ¥[]÷Qßý£hŽéx„\Õ56ñ³ôœIê%*=ÄM%¸d5¿É-öÒAZ܄¤ÿ& Áâ*¨'ˆ³T…3Ê\rk+¹…EŸø§fŽŸ@ügì‘ìÁîTNž…c§>Φ×Ä=¬9˜vƒCªhø,ƒbÒ 9/L¿©£ÁaÍû„mتÆ'îJ.)“ÌK&·Ý´ýó¨:ƒ†i[å­`.‰aq‡{>ÓÔ0!Ô蚈¡A‰žuÝ"¶¹ò#¿®*‹›œ5œ.ð5ž³ ]Õ¼¨Øó/é0ÜðµÙÞØå»•%3 •¿ ð¹žOGçIsŽ»—Õ( +#4"úˆéãÛ¯Ž“L)Á¡Õfþí®,ɦ"¼ì'JÙ«[ ~ÆßÓ{”TÃeADÒº”CT”ŒÎ& ¦‹!‡æ[p“ëjê¨$\Æy€ŒpNÂìçqŠÞ­õèç%kïØéhˆŽúèÇðdíºôaó½ á ®LÕ sÕ Ó^\½Oʖ÷9ÍóîÉýÛñîø ZiÚ,&‘}tnÕìiã™Sàu%Km䮣w܈ֺç¡÷®Wã/H¼cÌM]*]ãRîûƧ¾M©ìyãB0‹úè]µ¤`Ëí¿_ô8ü[änWØUýˆpãOÜkÞÕ~^é–ßgGâþV¸ßàç%ÏÿòFä]~‰'‚yÖªv÷çýÖÿŽ[Qïú -.±‘£nÐö‘ÅÞ¨‰ãüU­N~¦]וõCñ¼F;Õ¼'¨¾É Æç”²PÒ4ɲlz!.ââI6»5¢ÆY2K“ÆëZ$]Ò©³"÷†Òwǀ=jE¢§3´Â‰ÎT»²ÊËî­êٟ¬\5–Ûꍞoš‡¡IkÖ㋧OáO…t Å÷Å–jcwTô»¡ò_˜l™ ´ ‹²$¢àÝgÓp э#:í×Ñ?°D @endstream +endobj +129 0 obj +965 +endobj +130 0 obj<>>>/Annots 17 0 R>>endobj +131 0 obj<>stream +xÚ¥S]o›0}ϯ¸‹4)“Á„ÉãºvZµnYCµgCœB¾Ì6úïç’ŒN1y¸c +8ÁîUüé´éßÜZÜF@ˆiàé^û‘©ð]€B¥¾¨JϘK |g}u9‡N2»3õpj§^;lU…\®]ù }/Œ†äqŒÿÆuðˆn\ò2ˆ¢0I’xžqä*IÇPË3j™„iþh+ ÉY´¨¯p]²â`ÐF“¾+lõS; {ÝÿÉò¡îÁEõmÅ ׏›­‘VZüS…k>›—@…Ös¨TڗZ"PØwuíí™î&ØŽ,ÉÄ >dhzÅN˜}Óþ&›~ ãf~Äü>C˜WÑlíXâ_õ«¶&Œ^†Žj.ð¨ë›”4È+…b @îúÉW©X3ס`Ü"¾ÂÔJ?ì/ž`V*Õ®‹ Z—(Õ:^’!48A§>Üö’ +û4((?9ºtcòR1_é<À=5•ZÙ¹MôÜföLùX©Ò‹º*M!ï”Bþnhzð‡åT;VW¨3îpÜßL?M…;œ¶ÀðÆ +lÃ͝j‹KÃz|¬Ø`¼jw™«‘ ¿p‰OmÝÍ·\L€wMnÜ.õÜ©ÁZJçLûoÄÏ_­roW·o‹é˜ü…1îŒ ûqKû¯t&—QêÞ`'e‹{u¤:Ò¸xOyG­ žC{IüëtFi 'Á^[õãòcò)éŸRendstream +endobj +132 0 obj +634 +endobj +133 0 obj<>>>>>endobj +134 0 obj<>stream +xÚ-‹±‚0E÷÷wÔíCE\5º™`(q®Ø +*%¶%þ¾V̽ÓÉ9/bˆï‹,¾îh+i~ÈÁ iÀÙf¶Â:×É®*J”½ oå4*¯ÇQÙA=§òNÉè&™E„i¾ÄØ6º~´ö†Ðh®µA;”A…Áø¾ûñ³¾Äh/éDÓÙ*Sendstream +endobj +135 0 obj +133 +endobj +136 0 obj<>>>>>endobj +137 0 obj<>stream +xÚ¥U[oÓ0~ï¯8Bê¤&‹4ix¬ ¤Þúâ¥îjäØ&v×v¿;N¯+Lå)¶Ïwó9ɯ‚È>2 q +eÕùPt®>å€#(f€Q?Œ!Í(¦Ý"¦¤žÂ}̈́¡5Œ”aRèËâ§-K!Wøº ÆYˆ]i1gÊ9Q®dJuY³ªÁÌ)è ¢j¥G´›Ä©)'Â8yà–s*ü9&aÉ̼ðäQKÞåêPMJYU–%ôë9 Ì­G$Q8pú>SAkÂO»±çp&Þ…™ä\.€R¢_‰#œƒY+kRÎ`Æ8Õ;ö¤Eã0u¨cÊiÙT97wtÊŒÙ3íAaz`¥ÃX.ê’þUØE ¡rÅïWëç‹Vhj|ÐÍè×lp¯d º~·I1wжÜ ¿®`‹|K»#gHŠÂðk1üî*­Ԇyª¢w·à†Ý/j%5ý‡ò¢&B+Û ¢\ÿ'ûkX{mܤ°—ð®wajŸ¦ö×ä³Ô¶Çµ¯6}ÛÚ=xX¨¤6 JÉÚ4»/jã(öÃ3é–Ćf'H³GÁf¬$ÂL.Û +[±x`OoÕNpšυÏâx6ø1†öZ'ÝAØ_Ù&ʹ³d»£t…³¼ª&—‡„û +O²=þ2»³áJ޹â~z6×uò’èËx×ICƒ3ë)LóCªh…óìlª£;´õE0O”KE-mnÝ%!ÂýÖ­PÔ?›õæö´Á›Û}ÊA˜¦–3Ž(qdÝGgSîOÉKòƒòÃশŸ_2ØþšîŒ‘ç{íO’d‰æÈEÈ- ‹Î·Îo)ê§endstream +endobj +138 0 obj +638 +endobj +139 0 obj<>>>>>endobj +140 0 obj<>stream +xڝVßoâ8~ç¯UZ]WJr$pPNêõەVÚv¹…¾õÅ$¼ +¶×vÊrýÍØ  ‚­€Æóó›oÿì¤ÐÅW +½½óUçnÚùósi +Ó9d7Iƒ›~rÓâú% áãô*tk…ëg­¹ ²~#ƒ¼4£§3l4·]ˆÓz~ÃçWµ>åӋßëó±*WF+ˏ]ûÓX‡ãw§Í̂ß3Írá6'Ò§cÈëóƒ ±G:ÎIŸÜO—Xî*V‚ÒN(iÁVZ+ãxÌp(ø\Hü.$8ÔÕFHÇÍÆãO0%oNr³Ÿˆÿ!ˆõ¾H]¹I©Ü‘"“E[w•G^6Ýè#„ë"’ AÚ¯-{½d@– Ÿò7#¸tŒ,Ú~ºm€®b%¦cS~Uǀµ(K0 +íy€+†Q[Î-8Ð"€¶Ö v1ÿnÊQLŠ8ó!?@©a?¤ÇY²‡‡§éÃ÷vm16Ս) •÷MrK˜ˆSQsŸá˜Ð‰J-™ÜºµŠé[Û%²!æÅKnjNê”J.j•†FÌz†)*]ò_˜ßk£j‘ +^®Å¼%¨©hA¸äå#ø Û¶Cs…óñæÊì¡G±¬—ˆâA®í‘ÊxÓ!eb˜pÁ߹潍â‰nRFݰúÞ²ß"|9&¼ä¹gƒïL¢)ò€æÒžå•²±·¾Ü-*Ö;µèÒ4.½B€¨¦ß9pöݧ—áÑ2‰ûï2ІÑ(N³“6`x8þA +,ÕZ›©Wíí¹A³qô1ž×ðÊʊ6°„®Wì¥\”‡Ñp®æªôÝBˆëÕjƍmámCIØ Í £M=Û ƒÕŠÙÄI舟@V®ÙÆRa¨ü&g6ç² f(Spá fŠ’Ûí®ðøãÄÀïõÚ¿ÚaÜp$©m¶¤R5k¼å’JVEÑPÙ°A·Ì³ÜÝâ§qxÈ†|^N ²ðÙ\>>>>>endobj +143 0 obj<>stream +xÚ¥VQOÛ0~ï¯8!MÚ$ÒÅiזI¼P14it„I{4ŽÓ˜9vf;tüûÐÒÂÚPÔ7û¾»ïûîÎéŸÆ FÀÊÞYÚûøåÈÒoFÒO ÍÞ_sç„Z€+8œ±(œâÖ~Hï0|„4áQ2ê}ø/]£ +˜VÎh`úž*%Ü®à ópS¡Ï@×®ªÔö±ÒQ¤Ÿ„ŸVÜ0®ÜèÊ ­>7åc8ñՑ”„âï@V°‰$I ¹\ђÃù,=¿Ú¤tKþ'•5·°0œ:n +!q Kì¥ÏÉ՚÷1, Ì ÷ Jz]›Œšßˆ®ß]Û ýѶ½´,)Lµ1œy™™¼IØ*I'«è4éêq!ãøíþbð3‡!EXÆsZKאóDÐ42hYXH++ ¤Ž܆böêâ lřÈ£^üº_ãÖúaܟø,)ÿëà{pèÿKà©äZJ½ô&7~Z U%°<ò òB|:ïŸí6"³º¼E簧ӂÊÐF s<ùªX±“o3«Äf“Ár×x V‰Ù:1®L¼o|^’¼8zÂìVôMàÆv#»ˆ‘!gW>åä­2¦ZÖåžáÍhâök3ÒFïíD›ôÀfÌé‚Ã%5 ±CÀL›_š‡fQ=¢l@ ÷Àép‡ƒ”aJá¶|ƒÛªfwµuϳԖ?>L[+ìÃ"ÉsךvŒ §áÅ~ìtµ:¤*[_Üjçt¹iþ^w·ê¿à±'Û¾ 'ô^Z±æ©°‡`Òv”à|Âï|H1½™_õÎÝÒ÷ðÆúí¿¤ª¦Òƒ"2:ÁØhŒӝ †ã!R +AdàÎÓޏÞ?n•àendstream +endobj +144 0 obj +666 +endobj +145 0 obj<>>>>>endobj +146 0 obj<>stream +xڕWßOã8~篭t:Вl’¦¿î´,âönº'ñb—œ8k;”Þ_3vÒ6–¬(­ê|žù¾oƓôÇQ þÅ0Ñkž}™}ú#…8†Ù¯Œ&i8Yv<[r8™=âÅQ}ñø™ÉŠûµfÃ10ýPå¼° Xܓã‚(_¥…5¿gó¥ÿB˜øÓ8Á«¸¤4Dá`˜ç¡9…8õ$‚Á ‰kÍ­]õÆÍ¢xhçF\2 +ӆì‡@Aéð%Á?€*­PH£²,9˸fK«JP‹š{à°v鮸oE•ßs} +ê¬°’ÃÝqe*&åš@ijǃ0¡ì !yÁr~wr +¬È\˜ŒY™4êÎÝêùǏðÄ×+¥3ä£9,ÅÃRâ¿å™ß7W¹sRŠ‚{ˆ°Lйøg¿yíLI:–.Hœò_@–ÐV ¸ø{vq³1wL;ښF¾Æ—9‰½r>™ƒæ.””j…%¨]Eze‰f¬–®ËÂÅ£ôfMoç¨ Áä’#ðnUßñ¹äzΩ²d–+w)>»¦ü°¡5_²9Ppƒ¾Q‘™'È3Ïï=';ÙÞp“J_;¸±¿aò¦ù6gþ®º:W÷ Õ©»GMPûք…V9c«`E`J>‹uc«SŽ'PsÉÜ@ئ·ïŽ;Ù +õ*YáÝ œuÚ½!ÖƘ»ñi%¤$õr›ŠêéRr˱W˜ÙÆÅ/Hق&~À¨¹ ؉DQ'q+“ouÔV•$/u}ÛuZkÓk’½moœ¼öWs£dåœE¢[Q4ôÄ —†LqC5þbG‹]27Q½$)ùèw£—‰‹BÓÀ´þ¦þÂÈä.=ÏV`Ão‰vÒçì‰ï–CâÔÆ˜ÈªØ”ïòJZ‘½·žÚ=ß'tÇ`ýÌb]»ò£âÆî?ùgÙcelcâŸõâ CaÑ1-zŽƒeÅÛ§Þc.º ˆ¦0­£OŠpàKñä'„%—窰ZIj¥µªt·N\òga0Ë{scCëçFÀÏÞcÛ-Šá"ª}ÐTÔo¡¾¸s%±?È­¬!´Ç¹e÷²Û›¦Êñ.Ž3¤âG*šó+Úlx}³ÌÄbÁ5wbSû3¬YǃEÉØK½Ò ˜$Ð8 XX\%ςtH‹Ótwѯ]̎¢»~ûvódŒ³7N§ø>ŠÃÒÆ›åí[àINk0>Ù¤ÁÉhŒ­ƒûzu«fیtŒ¦˜ª§‡í©Ãa÷éÖ¿4¾ád.,k‹¹,2ñ ÚRεȍz¯ÍÒIÿÁà°=µ8ì>-ƒÔςó5ëœöñ؊ù‹žüƒ‚=o‹v@T2é?¶§(‡}kÖMšY‡%Â8ñø~} ·jaWôãä»áÚÀ7VT~¬Ôà8¥Å4#¥hϏ9TüÏÑÿ»Úû×endstream +endobj +147 0 obj +1228 +endobj +148 0 obj<>>>>>endobj +149 0 obj<>stream +xڝ’ÍnÛ0„ïzŠA€©¢¬Èv’ÀrH‘ÖÊ-Z^ٌ)R%)»yû’;?§‚'rw¿ÙðoĐúÃ0É0.P5ÑM}ÿ9ËQÖ¾RLY’¡\®WϝuB­á6„wáNh…§Ñ­–Ú<C×à +w _Óyùì190qV$yÀ”~ø,Ö°o€«–LEʝA·=÷J¶×9¶zx©‚˜…PAK­ 4]µ[:v`«ô2láµÙx°à!/º3p$i'¬‡þöL1 kúâ¬ßòd‹/·D-$)Þæ¿ÊùŸ÷>ãžpât(‡òèÀx?47ë® lÛR%jAöÄÇIµÑÏÒidišàús‡Y·F¯ºÊCøÿKÉ«mÌÕ*Þo„#ß(”»€¿HǎˎÂÓ±R¢á§‘ZÐ?g¨!ùâãw¤,%ƒ•éÁ ++fÉ¥ÿ:½Úíãà ]»=7„GKpÏUÇeЇÞx’¥ÿ÷»òIžLѳËð0/£ßÑ+IÚÞsendstream +endobj +150 0 obj +391 +endobj +151 0 obj<>>>>>endobj +152 0 obj<>stream +xÚ-‹±‚0E÷~ÅaiUÐQ‰&&ÊÆò!ÐÆÒÆßWÔÜ3œûdÉgët¡žØQ²ÕyÎ![ðto‘‰² òòV 0­{‘U(geg\I{C9°è×Fÿ˜§‹™ˆ7øŠC3øÙõºƒ{(ä¼%׍*ÈÍhl´ ËDZÎ'Éîì (,ƒendstream +endobj +153 0 obj +143 +endobj +154 0 obj<>>>/Annots 56 0 R>>endobj +155 0 obj<>stream +xÚ͛Ýs¹ ÀßýWìãÝL­,¹ß¯I{Ó|ô¬L_ò²–×¶î´Zw%%Mÿú¸ ®mr=s¶”Ì8fü,‚ ~ø?g*Šá¯Š +%y´jÏÞ.ÏÞ¼«"G˛HeU”i´¼þiY_mš¨»‰.ºí¾Ùîw?/?ûÛò,^Ä@À/ +¿üöQžd‹2j#ø'åÆ&ºDøD¾¿Þ¼Ë"¥ðÇ¡^¢ðã>÷ÍM½jð‡$É".øÏÅÉÿQOZÃÓz‘ƒY +µPÜ`³¼y—²`r@ øòÇnߴѓPÁiA=]d.•û™öé[Ó[7ß—ªEuBF Ù-®ÀÚ¨La$ÔࢵT¼0.úK·:´àšOÛK能t6phÔoy޽ôBŸ†½”wáee_ÁRðqéûÁÁÆU–•f|Êc¨AìTÀúsXÔkçO3„^ex¢áî”Vûz»_ooŸ† ý6ª2ptÆÝéœE#´api¼(\÷?tìèø—I–W&êf865 /YS]Þ5‹°xŠö•D궤ð +X=Q8ù’Gý#¯ƒtӚð)äV^ÈøYnÂ0Æ4Æ•eÅà&gŽŠK¸â~‹jVwÛnÓÝþ@`¦àO)K¦s¥‰‰Â0¦œÂ\iJ!ø×îʪ:ý 4à$†°ÙFàô¶! Bãð.6õn×ì¨î9ᇠÑÃknVµiˆÁ*³Æß­7û¦7C…Lœôô††'&®å%&ÓÍS$›þéõ/Ôqý«)Œû÷K¿þÆöoÊOÍ~™ßdi›0W–0õÔM–VŠbÜÇfÿ½ëÿ€Ìbbœ>Í(yK²æ’Œ¾¤$KóŒ€öefª'‡F½L •e“æQ w3çËΛԅºY듏ÄÝÌÚûRŸPF×ϧ¶â~F…Ë ‰Àz+ wœ,ÀD*ÍZ:‰DZV¤{Sæ¨ñX¥—f4¸ÃU»Þû &H¸•Th/Éå~͑»Ùyl/´i›•º,+``7'"Je@åzú±¬€ã\6ª£Mchö’„ø2Æõa"ö%%Å÷‹»®ó/?¡oiqµ‡3ªâܛˆì€¨¿tҘÉÛÕ "„Œ®S“prüÌÔFן¸4u"Ô1Páa‹ã~ÆS¾$`œÂBÈáY~ºß¯»-%}}£2`vXëXç{©!Ì®ôbæ€Ð§£®Ò¥q?ó>6ûõý¦ñ©Ç¸Ët€V€‰Ýýšêr]ßî£'UI%FjŒFOªŠ÷wÍêp€±°ª€ˆêÀ¸»š‘ß…2¦LÇŠû+‘ß½ËFZ<¦†)qxV€—ûzð¥,A^‰'¦.˜wÓwž&©´êÁh­ÀËIõ6҅æ×Â*g¨]ÛÖÛëó®·æø¼ˆÿ|g ¹_™QubüÃ4„û•ùsœQäÅÝùL×cû…qþdz4ò +I³ù3ÜÎÒÈ+ 䳝βªã´ù\—c”Ö1$%U‰Aþ»¹2a1~=|ð½BQ9„'JÔ¾Wh®­êíªÙøÝo€û©mݏºu°¸ª˜¸°,u@•1Æý|9kÔÆb!žÑ +0î×Î̌JOäµòî““ƒiŸLß?²ON`Oiòqâß'[˜ÙÎ:4êeJhŸl1°sŒ] w3úöºî¯½Üqˆx¶3áåéH›Q5*IƒÊ|2Hq²fÄëÕ#»‚ +\ö%‰6©®0áÊ4ÛÛ&IB ï}³múzã)G=Vw°ÜÏ8i­ä´.IŸ6UªâÝ{{ujÙ!‚Ïë˜68›f8;útWS¹4  ?“eÚ¿O> êCs½öDR©ŽÙ²À•ìÀH€ºþ_ó_ºÕ!ÇÁˆ’ Œ¶üqïƒIu€¿q`,@0”PTŽwú.ŠxÝ¡çWñKœ].Îø°¯¦¨%\.æ×Á]µÔÇ"Mc“4+À@¿Ó u̸Ô] 0ìS¿n¶P©Á²7÷¼åq•öÛZWöÞQk´µ®qäXß#iÂÁYûndë³õ¨õ0.‹˜õ¶ÛßùêáQg+s—Æö}ÌúÚ{)0ªÁŠC'Æu7¾xQ‰9Ðq6I^ÿ”Ê-på:(+`g´¾ç㶗 t‚Ϙ@-á„%?™ež›Ãc‹ô%¡ŒNˆGA.Š,ê·z{ë‹€I+Gqp$`q^·Ú¸+ÃbÝe‘€e}®où”éµkàÌç9Px G-1óyAåÓÇó/÷þãÎdD™CfeŠÅc'úG߯”ñ³"“®¨%Œ”¥ÏȆËd+‡eҙ¹p@åxHä¢XÀ ÞöëÛ»ý¶ÙíèÁӑÊ_•¬œT¢ê –°r?«êhd Ic œci Ë* ^Œ,ì}ݶµÿh¨pj•)Ž,î¢ë{ ¹\üÞ>OÞEiÍï¢J4¥vßEi=Ú+ï† P‰^Nx,ÎH±BO+±rY,À¬‹»º¯WøôÈS¢ JkYì2­3?û+ÕëvòA`Dýc»º3§vøØç|7èqÌyÞ¸G»y>æ‡jsýÏÒÈ?$Í +¨9— B}ð?Æ ›é–GâðX€y3üYøo«”h4’fÒÙ¥ÜKqâÂXÀ>쬽ÛI¡§z:P+À´u»æiÊ^ÿ]lpÆò˜ß¾¨¡%f,Wö +¦ìGè +c€A©˜¹0¼Â4±<þe– +¼ViA×FfbMc¬yUZr¦o½~#”ÉÚÊEqùð’çÄÉz¬E•ØgŸx@-áQ‰}¢¹ª70êӉRåÒ¬@6«âÕq;‡/ƒ\ 0ÌL¦9¸9òž#hmmßx–èQZ¹ÉU›Ñüõú÷Ã.t~7ê·Æ4‰K³3l-”ÑÖxÐã¢XÀ þ~ðžÝÊô¢¢œ XÀ ¾þ´„¸òõgÿ«ŠräUx$éòX \& +],qÏê’X@Ó‘¯Bu±¬Ë§æ²Ç|é±AϋǦŠ[Âób~_:ß÷,¼Cò¬@9'Û uÊÏS 0ì²Þzs[äs-˜Tf»L`æW,κÞ牂ÛÜjŠ´Œôù¢ÔÆí­Æäë°XÀ¾öy£ÐÆ÷iñ0ÓÃî–˜5úcñçï2”ùUŒñCÆÃürà\™ P®ì/\}ù|]v7ûïußD_vx,ð¡Þê ý2@t׺füëìÿ%¤ëÑendstream +endobj +156 0 obj +2689 +endobj +157 0 obj<>>>>>endobj +158 0 obj<>stream +xÚ+ä2T0BCc3JÎår +áÒw³P04TIS04³Ô3U072PIÑp VÎO+)O,JU-N-*VðMÌ+MÌÑ Éâ҅¨Õ…*ÎÌ º†prÇvMendstream +endobj +159 0 obj +94 +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<>1<>2<>4<>]>>>>endobj +xref +0 201 +0000000000 65535 f +0000000015 00000 n +0000000219 00000 n +0000001785 00000 n +0000001859 00000 n +0000001937 00000 n +0000002014 00000 n +0000002093 00000 n +0000002169 00000 n +0000002250 00000 n +0000002308 00000 n +0000002360 00000 n +0000002445 00000 n +0000002469 00000 n +0000002574 00000 n +0000002598 00000 n +0000002649 00000 n +0000002734 00000 n +0000002758 00000 n +0000002862 00000 n +0000002967 00000 n +0000003072 00000 n +0000003176 00000 n +0000003281 00000 n +0000003386 00000 n +0000003491 00000 n +0000003596 00000 n +0000003701 00000 n +0000003806 00000 n +0000003911 00000 n +0000004015 00000 n +0000004120 00000 n +0000004225 00000 n +0000004330 00000 n +0000004435 00000 n +0000004540 00000 n +0000004645 00000 n +0000004750 00000 n +0000004854 00000 n +0000004959 00000 n +0000005064 00000 n +0000005169 00000 n +0000005274 00000 n +0000005379 00000 n +0000005484 00000 n +0000005589 00000 n +0000005694 00000 n +0000005799 00000 n +0000005904 00000 n +0000006009 00000 n +0000006114 00000 n +0000006219 00000 n +0000006324 00000 n +0000006429 00000 n +0000006534 00000 n +0000006639 00000 n +0000006744 00000 n +0000007027 00000 n +0000007059 00000 n +0000007091 00000 n +0000007598 00000 n +0000007646 00000 n +0000007694 00000 n +0000007742 00000 n +0000007790 00000 n +0000007838 00000 n +0000007886 00000 n +0000007934 00000 n +0000007982 00000 n +0000008030 00000 n +0000008078 00000 n +0000008126 00000 n +0000008174 00000 n +0000008222 00000 n +0000008270 00000 n +0000008318 00000 n +0000008366 00000 n +0000008414 00000 n +0000008462 00000 n +0000008510 00000 n +0000008558 00000 n +0000008606 00000 n +0000008654 00000 n +0000008702 00000 n +0000008750 00000 n +0000008798 00000 n +0000008846 00000 n +0000008894 00000 n +0000008942 00000 n +0000008990 00000 n +0000009038 00000 n +0000009086 00000 n +0000009134 00000 n +0000009182 00000 n +0000009230 00000 n +0000009278 00000 n +0000009326 00000 n +0000009374 00000 n +0000009422 00000 n +0000009470 00000 n +0000009698 00000 n +0000009849 00000 n +0000016195 00000 n +0000016217 00000 n +0000016311 00000 n +0000016413 00000 n +0000016433 00000 n +0000016586 00000 n +0000017504 00000 n +0000017525 00000 n +0000017655 00000 n +0000017926 00000 n +0000017947 00000 n +0000018086 00000 n +0000019004 00000 n +0000019025 00000 n +0000019164 00000 n +0000020591 00000 n +0000020613 00000 n +0000020752 00000 n +0000021638 00000 n +0000021659 00000 n +0000021771 00000 n +0000021958 00000 n +0000021979 00000 n +0000022118 00000 n +0000022826 00000 n +0000022847 00000 n +0000023009 00000 n +0000024045 00000 n +0000024066 00000 n +0000024228 00000 n +0000024933 00000 n +0000024954 00000 n +0000025066 00000 n +0000025270 00000 n +0000025291 00000 n +0000025439 00000 n +0000026148 00000 n +0000026169 00000 n +0000026326 00000 n +0000027322 00000 n +0000027343 00000 n +0000027482 00000 n +0000028219 00000 n +0000028240 00000 n +0000028397 00000 n +0000029696 00000 n +0000029718 00000 n +0000029866 00000 n +0000030328 00000 n +0000030349 00000 n +0000030461 00000 n +0000030675 00000 n +0000030696 00000 n +0000030849 00000 n +0000033609 00000 n +0000033631 00000 n +0000033743 00000 n +0000033908 00000 n +0000033928 00000 n +0000033983 00000 n +0000034088 00000 n +0000034232 00000 n +0000034335 00000 n +0000034440 00000 n +0000034605 00000 n +0000034713 00000 n +0000034828 00000 n +0000034933 00000 n +0000035041 00000 n +0000035149 00000 n +0000035265 00000 n +0000035363 00000 n +0000035529 00000 n +0000035646 00000 n +0000035765 00000 n +0000035889 00000 n +0000036014 00000 n +0000036164 00000 n +0000036305 00000 n +0000036414 00000 n +0000036566 00000 n +0000036705 00000 n +0000036835 00000 n +0000036959 00000 n +0000037095 00000 n +0000037222 00000 n +0000037336 00000 n +0000037459 00000 n +0000037575 00000 n +0000037724 00000 n +0000037853 00000 n +0000037990 00000 n +0000038120 00000 n +0000038245 00000 n +0000038348 00000 n +0000038485 00000 n +0000038590 00000 n +0000038729 00000 n +0000038863 00000 n +trailer +<> +startxref +39089 +%%EOF diff --git a/doc/sum.shtml b/doc/sum.shtml new file mode 100644 index 0000000000..7c69609ee3 --- /dev/null +++ b/doc/sum.shtml @@ -0,0 +1,560 @@ + + + + + + + CUPS Software Users Manual + + + +

Preface

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

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-edge" and "-o +sides=two-sided-long-edge" 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-edge filename ENTER
    +% lp -o sides=two-sided-long-edge 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
    +
+ +

N-Up Printing

+ +

The "-o number-up=value" option selects N-Up printing. N-Up +printing places multiple document pages on a single printed +page. CUPS supports 1-Up, 2-Up, and 4-Up formats: + +

    +% lp -o number-up=1 filename ENTER
    +% lp -o number-up=2 filename ENTER
    +% lp -o number-up=4 filename ENTER
    +
+ +

The default format is 1-Up. + +

Setting the Brightness

+ +

You can control the overall brightness of the printed output using the +"-o brightness=percent" option: + +

    +% 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. The default gamma is 2200 which matches the +sRGB specification. + +

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.shtml b/doc/svd.shtml new file mode 100644 index 0000000000..f5bdbf9a72 --- /dev/null +++ b/doc/svd.shtml @@ -0,0 +1,156 @@ + + + + + + CUPS Software Version Description + + + +

Scope

+ +

Identification

+ +This software version description document provides release information for the +Common UNIX Printing System ("CUPS") Version 1.1. + + + +

Document Overview

+ +

This software version description document is organized into the following +sections:

+ + + + + +

Additions

+ +CUPS 1.1 includes many new features from the 1.0.x releases. + +

Filters

+ +

imagetoraster, imagetops

+ +The image file filters have been upgraded to support conversion of Microsoft +Bitmap ("BMP") files. + +

pstoraster

+ +

The pstoraster filter has been integrated with GNU GhostScript 5.50. The +new RIP supports most Level 3 PostScript language features and much better +color management for the sample printer drivers. + +

User-Defined Printers and Options

+ +

The new lpoptions command allows users to configure default +document options and create additional "instances" of existing printers, +each with unique options. + +

The lp, lpr, and lpstat commands +have been upgraded to use this option and printer instance information +automatically. + + + +

Changes

+ +CUPS 1.1 includes many changes from the 1.0.x releases. + +

Directory Structure

+ +The directory structure in CUPS 1.1 has been modified to conform to the +Filesystem Hierarchy Standard, 2.0. The following table describes the +new file locations. + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table N: Directory structure changes from CUPS 1.0.x to 1.1.x.
DescriptionCUPS 1.0.xCUPS 1.1.x
Backends/var/cups/backend/usr/lib/cups/backend
CGI programs/var/cups/cgi-bin/usr/lib/cups/cgi-bin
Configuration files/var/cups/conf/etc/cups
Documentation/usr/share/cups/doc/usr/share/doc/cups
Filter programs/var/cups/filter/usr/lib/cups/filter
Interface scripts/var/cups/interfaces/etc/cups/interfaces
Locale data/usr/lib/locale/usr/share/locale
Log files/var/cups/logs/var/log/cups
PPD files/var/cups/ppd/etc/cups/ppd
Request files/var/cups/requests/var/spool/cups
+ +

IPP Implementation

+ +

CUPS 1.1 is based on version 1.1 of the Internet Printing Protocol, +and implements the set-job-attributes extension operation. + +

Two new CUPS-specific extension operations are provided to determine +which devices and printer drivers are available on the system. + +

The CUPS-get-printers and CUPS-get-classes +operations have been upgraded to support limited filtering based upon +the printer-type, printer-location, +printer-info, and printer-make-and-model +attributes. + +

The CUPS-add-printer operation now supports the +ppd-name attribute to specify a locally-available PPD +file rather than sending the PPD file from the client with the request. + +

Further information on the CUPS implementation of IPP can be found +in CUPS-IPP-1.1. + + + + + diff --git a/doc/system-overview.shtml b/doc/system-overview.shtml new file mode 100644 index 0000000000..08449c55ac --- /dev/null +++ b/doc/system-overview.shtml @@ -0,0 +1,20 @@ +

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 5.50) and an image file RIP that +is used to support non-PostScript printers. diff --git a/filter/Makefile b/filter/Makefile new file mode 100644 index 0000000000..6f82de273f --- /dev/null +++ b/filter/Makefile @@ -0,0 +1,191 @@ +# +# "$Id$" +# +# Filter makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2000 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 \ + rastertoepson rastertohp + +HPGLOBJS = hpgl-attr.o hpgl-config.o hpgl-main.o hpgl-prolog.o \ + hpgl-char.o hpgl-input.o hpgl-polygon.o hpgl-vector.o +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 +FORMOBJS = form-attr.o form-main.o form-ps.o form-text.o form-tree.o +OBJS = $(HPGLOBJS) $(IMAGEOBJS) $(FORMOBJS) \ + imagetops.o imagetoraster.o common.o pstops.o raster.o \ + rastertoepson.o rastertohp.o texttops.o textcommon.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) $(LIBCUPSIMAGE) + + +# +# Install all targets... +# + +install: + -$(MKDIR) $(SERVERBIN)/filter + $(CP) $(TARGETS) $(SERVERBIN)/filter + -$(MKDIR) $(INCLUDEDIR)/cups + $(CP) raster.h $(INCLUDEDIR)/cups + -$(MKDIR) $(LIBDIR) + $(CP) $(LIBCUPSIMAGE) $(LIBDIR) + -if test $(LIBCUPSIMAGE) != "libcupsimage.a"; then \ + $(RM) `basename $(LIBCUPSIMAGE) .2`; \ + $(LN) $(LIBCUPSIMAGE) `basename $(LIBCUPSIMAGE) .2`; \ + fi + + +# +# formtops +# + +formtops: $(FORMOBJS) common.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ $(FORMOBJS) common.o $(LIBS) -lm +$(FORMOBJS): form.h + + +# +# hpgltops +# + +hpgltops: $(HPGLOBJS) common.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ $(HPGLOBJS) common.o $(LIBS) -lm +$(HPGLOBJS): hpgltops.h + + +# +# libcupsimage.so.2, libcupsimage.sl.2 +# + +libcupsimage.so.2 libcupsimage.sl.2: $(IMAGEOBJS) raster.o ../Makedefs + echo Linking $@... + $(DSO) $@ $(IMAGEOBJS) raster.o $(DSOLIBS) -lm + $(RM) `basename $@ .2` + $(LN) $@ `basename $@ .2` + + +# +# libcupsimage.a +# + +libcupsimage.a: $(IMAGEOBJS) raster.o ../Makedefs + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(IMAGEOBJS) raster.o + $(RANLIB) $@ + +$(IMAGEOBJS): image.h +raster.o: raster.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 raster.h + + +# +# pstops +# + +pstops: pstops.o common.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ pstops.o common.o $(LIBS) +pstops.o: common.h + + +# +# rastertoepson +# + +rastertoepson: rastertoepson.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ rastertoepson.o -L. -lcupsimage $(LIBS) +rastertoepson.o: raster.h + + +# +# rastertohp +# + +rastertohp: rastertohp.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ rastertohp.o -L. -lcupsimage $(LIBS) +rastertohp.o: 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..b41cc4ec32 --- /dev/null +++ b/filter/common.c @@ -0,0 +1,255 @@ +/* + * "$Id$" + * + * Common filter routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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; + + fprintf(stderr, "DEBUG: Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f\n", + PageWidth, PageLength, PageLeft, PageBottom, PageRight, PageTop); + } + + 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 && + strncasecmp(val, "two-", 4) == 0) + Duplex = 1; + else if ((val = cupsGetOption("Duplex", num_options, options)) != NULL && + strncasecmp(val, "Duplex", 6) == 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..c92a121186 --- /dev/null +++ b/filter/common.h @@ -0,0 +1,67 @@ +/* + * "$Id$" + * + * Common filter definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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/form-attr.c b/filter/form-attr.c new file mode 100644 index 0000000000..362b6e0654 --- /dev/null +++ b/filter/form-attr.c @@ -0,0 +1,37 @@ +/* + * "$Id$" + * + * CUPS form attribute routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 "form.h" + + +/* + * End of "$Id$". + */ diff --git a/filter/form-main.c b/filter/form-main.c new file mode 100644 index 0000000000..c35b11a4c8 --- /dev/null +++ b/filter/form-main.c @@ -0,0 +1,37 @@ +/* + * "$Id$" + * + * CUPS form main entry for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 "form.h" + + +/* + * End of "$Id$". + */ diff --git a/filter/form-ps.c b/filter/form-ps.c new file mode 100644 index 0000000000..48e6a40d3a --- /dev/null +++ b/filter/form-ps.c @@ -0,0 +1,37 @@ +/* + * "$Id$" + * + * CUPS form PostScript routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 "form.h" + + +/* + * End of "$Id$". + */ diff --git a/filter/form-text.c b/filter/form-text.c new file mode 100644 index 0000000000..c128890d1a --- /dev/null +++ b/filter/form-text.c @@ -0,0 +1,37 @@ +/* + * "$Id$" + * + * CUPS form text routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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 "form.h" + + +/* + * End of "$Id$". + */ diff --git a/filter/form-tree.c b/filter/form-tree.c new file mode 100644 index 0000000000..2c27820def --- /dev/null +++ b/filter/form-tree.c @@ -0,0 +1,38 @@ +/* + * "$Id$" + * + * CUPS form document tree routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2000 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 "form.h" + + +/* + * End of "$Id$". + */ diff --git a/filter/form.h b/filter/form.h new file mode 100644 index 0000000000..c05e0d67aa --- /dev/null +++ b/filter/form.h @@ -0,0 +1,34 @@ +/* + * "$Id$" + * + * CUPS form header file for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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" + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-attr.c b/filter/hpgl-attr.c new file mode 100644 index 0000000000..0056f3af1b --- /dev/null +++ b/filter/hpgl-attr.c @@ -0,0 +1,442 @@ +/* + * "$Id$" + * + * HP-GL/2 attribute processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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) + { + MiterLimit = 3.0f; + LineCap = 0; + LineJoin = 0; + } + else for (i = 0; i < (num_params - 1); i += 2) + switch ((int)params[i].value.number) + { + case 1 : + LineCap = 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 : + LineJoin = 0; + break; + case 5 : + LineJoin = 2; + break; + default : + LineJoin = 1; + break; + } + break; + case 3 : + MiterLimit = 1.0 + 0.5 * (params[i + 1].value.number - 1.0); + break; + } + + if (PageDirty) + { + printf("%.1f setmiterlimit\n", MiterLimit); + printf("%d setlinecap\n", LineCap); + printf("%d setlinejoin\n", LineJoin); + } +} + + +/* + * '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 && params[0].value.number <= 1024) + PenCount = (int)params[0].value.number; + else + fprintf(stderr, "WARNING: HP-GL/2 \'NP\' command with invalid number of parameters (%d)!\n", + num_params); + + for (i = 0; i <= PenCount; i ++) + Pens[i].width = PenWidth; + + PC_pen_color(0, NULL); +} + + +/* + * '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) + { + Pens[i].rgb[0] = standard_colors[i][0]; + Pens[i].rgb[1] = standard_colors[i][1]; + Pens[i].rgb[2] = standard_colors[i][2]; + } + else + { + Pens[i].rgb[0] = 0.0f; + Pens[i].rgb[1] = 0.0f; + Pens[i].rgb[2] = 0.0f; + } + + if (PageDirty) + printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], + Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], + Pens[PenNumber].width * PenScaling); + } + else if (num_params == 1 || num_params == 4) + { + i = (int)params[0].value.number; + + if (num_params == 1) + { + Pens[i].rgb[0] = standard_colors[i & 7][0]; + Pens[i].rgb[1] = standard_colors[i & 7][1]; + Pens[i].rgb[2] = standard_colors[i & 7][2]; + } + else + { + Pens[i].rgb[0] = params[1].value.number; + Pens[i].rgb[1] = params[2].value.number; + Pens[i].rgb[2] = params[3].value.number; + } + + if (PageDirty && i == PenNumber) + printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], + Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], + Pens[PenNumber].width * PenScaling); + } + 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) + { + pen = (int)params[1].value.number; + + Pens[pen].width = w; + + if (PageDirty && pen == PenNumber) + printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], + Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], + Pens[PenNumber].width * PenScaling); + } + else if (num_params < 2) + { + /* + * Set width for all pens... + */ + + for (pen = 0; pen <= PenCount; pen ++) + Pens[pen].width = w; + + if (PageDirty) + printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], + Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], + Pens[PenNumber].width * PenScaling); + } + 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); + + if (PageDirty) + printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], + Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2], + Pens[PenNumber].width * PenScaling); +} + + +/* + * '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..aa29ba909b --- /dev/null +++ b/filter/hpgl-char.c @@ -0,0 +1,498 @@ +/* + * "$Id$" + * + * HP-GL/2 character processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 */ + + + /* + * Set default font attributes... + */ + + AlternateFont.typeface = 48; + AlternateFont.posture = 0; + AlternateFont.weight = 0; + AlternateFont.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 : + AlternateFont.height = params[i + 1].value.number; + break; + case 5 : + AlternateFont.posture = (int)params[i + 1].value.number; + break; + case 6 : + AlternateFont.weight = (int)params[i + 1].value.number; + break; + case 7 : + AlternateFont.typeface = (int)params[i + 1].value.number; + break; + } + + /* + * Define the font... + */ + + if (PageDirty) + printf("/SA {\n" + " /%s%s%s%s findfont\n" + " [ %f %f %f %f 0.0 0.0 ] makefont\n" + " setfont\n" + "} bind def\n", + AlternateFont.typeface == 48 ? "Courier" : "Helvetica", + (AlternateFont.weight != 0 || AlternateFont.posture != 0) ? "-" : "", + AlternateFont.weight != 0 ? "Bold" : "", + AlternateFont.posture != 0 ? "Oblique" : "", + AlternateFont.x * AlternateFont.height, + -AlternateFont.y * AlternateFont.height, + AlternateFont.y * AlternateFont.height, + AlternateFont.x * AlternateFont.height); + + CharHeight[1] = AlternateFont.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 */ +{ + if (CharFont) + { + if (num_params == 2) + { + AlternateFont.x = params[0].value.number; + AlternateFont.y = params[1].value.number; + } + + if (PageDirty) + { + printf("/SA {\n" + " /%s%s%s%s findfont\n" + " [ %f %f %f %f 0.0 0.0 ] makefont\n" + " setfont\n" + "} bind def\n", + AlternateFont.typeface == 48 ? "Courier" : "Helvetica", + (AlternateFont.weight != 0 || AlternateFont.posture != 0) ? "-" : "", + AlternateFont.weight != 0 ? "Bold" : "", + AlternateFont.posture != 0 ? "Oblique" : "", + AlternateFont.x * AlternateFont.height, + -AlternateFont.y * AlternateFont.height, + AlternateFont.y * AlternateFont.height, + AlternateFont.x * AlternateFont.height); + } + } + else + { + if (num_params == 2) + { + StandardFont.x = params[0].value.number; + StandardFont.y = params[1].value.number; + } + + if (PageDirty) + { + printf("/SS {\n" + " /%s%s%s%s findfont\n" + " [ %f %f %f %f 0.0 0.0 ] makefont\n" + " setfont\n" + "} bind def\n", + StandardFont.typeface == 48 ? "Courier" : "Helvetica", + (StandardFont.weight != 0 || StandardFont.posture != 0) ? "-" : "", + StandardFont.weight != 0 ? "Bold" : "", + StandardFont.posture != 0 ? "Oblique" : "", + StandardFont.x * StandardFont.height, + -StandardFont.y * StandardFont.height, + StandardFont.y * StandardFont.height, + StandardFont.x * StandardFont.height); + } + } +} + + +/* + * '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 \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("%.3f %.3f %.3f %.2f SP ST\n", Pens[CharPen].rgb[0], + Pens[CharPen].rgb[CharPen], Pens[CharPen].rgb[2], + Pens[CharPen].width * PenScaling); + Outputf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], + Pens[PenNumber].rgb[PenNumber], Pens[PenNumber].rgb[2], + Pens[PenNumber].width * PenScaling); + } + + 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; + + if (PageDirty) + puts("SA"); + + 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 */ + + + /* + * Set default font attributes... + */ + + StandardFont.typeface = 48; + StandardFont.posture = 0; + StandardFont.weight = 0; + StandardFont.height = 11.5; + StandardFont.x = 1.0; + StandardFont.y = 0.0; + + /* + * Loop through parameter value pairs... + */ + + for (i = 0; i < (num_params - 1); i += 2) + switch ((int)params[i].value.number) + { + case 4 : + StandardFont.height = params[i + 1].value.number; + break; + case 5 : + StandardFont.posture = (int)params[i + 1].value.number; + break; + case 6 : + StandardFont.weight = (int)params[i + 1].value.number; + break; + case 7 : + StandardFont.typeface = (int)params[i + 1].value.number; + break; + } + + /* + * Define the font... + */ + + if (PageDirty) + printf("/SS {\n" + " /%s%s%s%s findfont\n" + " [ %f %f %f %f 0.0 0.0 ] makefont\n" + " setfont\n" + "} bind def\n", + StandardFont.typeface == 48 ? "Courier" : "Helvetica", + (StandardFont.weight != 0 || StandardFont.posture != 0) ? "-" : "", + StandardFont.weight != 0 ? "Bold" : "", + StandardFont.posture != 0 ? "Oblique" : "", + StandardFont.x * StandardFont.height, + -StandardFont.y * StandardFont.height, + StandardFont.y * StandardFont.height, + StandardFont.x * StandardFont.height); + + CharHeight[0] = StandardFont.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; + + if (PageDirty) + puts("SS"); + + 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..0496e08815 --- /dev/null +++ b/filter/hpgl-config.c @@ -0,0 +1,638 @@ +/* + * "$Id$" + * + * HP-GL/2 configuration routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 page_width, /* Actual page width */ + page_height; /* Actual page height */ + float scaling; /* Scaling factor */ + float left, right, /* Scaling window */ + bottom, top; + float width, height; /* Scaling width and height */ + float iw1[2], iw2[2]; /* Clipping window */ + + + /* + * Get the page and input window sizes... + */ + + if (FitPlot) + { + page_width = PageRight - PageLeft; + page_height = PageTop - PageBottom; + } + else + { + page_width = (P2[0] - P1[0]) * 72.0f / 1016.0f; + page_height = (P2[1] - P1[1]) * 72.0f / 1016.0f; + } + + fprintf(stderr, "DEBUG: page_width = %.0f, page_height = %.0f\n", + page_width, page_height); + + if (page_width == 0 || page_height == 0) + return; + + /* + * Set the scaling window... + */ + + switch (ScalingType) + { + case -1 : /* No user scaling */ + left = P1[0]; + bottom = P1[1]; + right = P2[0]; + top = P2[1]; + break; + + case 0 : /* Anisotropic (non-uniform) scaling */ + left = Scaling1[0]; + bottom = Scaling1[1]; + right = Scaling2[0]; + top = Scaling2[1]; + break; + + case 1 : /* Isotropic (uniform) scaling */ + left = Scaling1[0]; + bottom = Scaling1[1]; + right = Scaling2[0]; + top = Scaling2[1]; + + width = right - left; + height = top - bottom; + + if (width == 0 || height == 0) + return; + + if ((width * page_height) != (height * page_width)) + { + scaling = height * page_width / page_height; + if (width < scaling) + { + width = scaling; + left = 0.5f * (left + right - width); + right = left + width; + } + else + { + height = width * page_height / page_width; + bottom = 0.5f * (bottom + top - height); + top = bottom + height; + } + } + break; + + case 2 : + left = Scaling1[0]; + bottom = Scaling1[1]; + right = left + page_width * Scaling2[0]; + top = bottom + page_height * Scaling2[1]; + break; + } + + width = right - left; + height = top - bottom; + + if (width == 0 || height == 0) + return; + + /* + * Scale the plot as needed... + */ + + if (Rotation == 0 || Rotation == 180) + scaling = page_width / width; + else + scaling = page_width / height; + + if (FitPlot) + { + if (Rotation == 0 || Rotation == 180) + scaling *= page_width / PlotSize[1]; + else + scaling *= page_width / PlotSize[0]; + } + + /* + * Offset for the current P1 location... + */ + + if (FitPlot) + { + left = 0; + bottom = 0; + } + else + { + left = P1[0] * 72.0f / 1016.0f; + bottom = P1[1] * 72.0f / 1016.0f; + } + + /* + * Generate a new transformation matrix... + */ + + switch (Rotation) + { + case 0 : + Transform[0][0] = scaling; + Transform[0][1] = 0.0; + Transform[0][2] = -left; + Transform[1][0] = 0.0; + Transform[1][1] = scaling; + Transform[1][2] = -bottom; + break; + + case 90 : + Transform[0][0] = 0.0; + Transform[0][1] = -scaling; + Transform[0][2] = PageLength - left; + Transform[1][0] = scaling; + Transform[1][1] = 0.0; + Transform[1][2] = -bottom; + break; + + case 180 : + Transform[0][0] = -scaling; + Transform[0][1] = 0.0; + Transform[0][2] = PageLength - left; + Transform[1][0] = 0.0; + Transform[1][1] = -scaling; + Transform[1][2] = PageWidth - bottom; + break; + + case 270 : + Transform[0][0] = 0.0; + Transform[0][1] = scaling; + Transform[0][2] = -left; + Transform[1][0] = -scaling; + Transform[1][1] = 0.0; + Transform[1][2] = PageWidth - bottom; + break; + } + + fprintf(stderr, "DEBUG: Transform = [ %.3f %.3f\n" + "DEBUG: %.3f %.3f\n" + "DEBUG: %.3f %.3f ]\n", + Transform[0][0], Transform[1][0], Transform[0][1], + Transform[1][1], Transform[0][2], Transform[1][2]); + + if (FitPlot) + { + if (Rotation == 0 || Rotation == 180) + PenScaling *= page_width / PlotSize[1]; + else + PenScaling *= page_width / PlotSize[0]; + } + else + PenScaling = 1.0; + + if (PenScaling < 0.0) + PenScaling = -PenScaling; + + if (PageDirty) + { + printf("%.2f setlinewidth\n", Pens[PenNumber].width * PenScaling); + + if (IW1[0] != IW2[0] && IW1[1] != IW2[1]) + { + iw1[0] = IW1[0] * 72.0f / 1016.0f; + iw1[1] = IW1[1] * 72.0f / 1016.0f; + iw2[0] = IW2[0] * 72.0f / 1016.0f; + iw2[1] = IW2[1] * 72.0f / 1016.0f; + + printf("initclip MP %.3f %.3f MO %.3f %.3f LI %.3f %.3f LI %.3f %.3f LI CP clip\n", + iw1[0], iw1[1], iw1[0], iw2[1], iw2[0], iw2[1], iw2[0], iw1[1]); + } + } +} + + +/* + * '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); + + PenWidth = 1; + + 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] = 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; + 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]; + + if (ScalingType < 0) + { + Scaling1[0] = P1[0]; + Scaling1[0] = P1[1]; + Scaling2[0] = P2[0]; + Scaling2[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]; + + if (ScalingType < 0) + { + Scaling1[0] = P1[0]; + Scaling1[0] = P1[1]; + Scaling2[0] = P2[0]; + Scaling2[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] = PageLeft / 72.0f * 1016.0f; + IW1[1] = PageBottom / 72.0f * 1016.0f; + IW2[0] = PageRight / 72.0f * 1016.0f; + IW2[1] = PageTop / 72.0f * 1016.0f; + } + else if (num_params == 4) + { + + if (ScalingType < 0) + { + IW1[0] = params[0].value.number; + IW1[1] = params[1].value.number; + IW2[0] = params[2].value.number; + IW2[1] = params[3].value.number; + } + else + { + IW1[0] = (Transform[0][0] * params[0].value.number + + Transform[0][1] * params[1].value.number + + Transform[0][2]) / 72.0f * 1016.0f; + IW1[1] = (Transform[1][0] * params[0].value.number + + Transform[1][1] * params[1].value.number + + Transform[1][2]) / 72.0f * 1016.0f; + IW2[0] = (Transform[0][0] * params[2].value.number + + Transform[0][1] * params[3].value.number + + Transform[0][2]) / 72.0f * 1016.0f; + IW2[1] = (Transform[1][0] * params[2].value.number + + Transform[1][1] * params[3].value.number + + Transform[1][2]) / 72.0f * 1016.0f; + } + + fprintf(stderr, "DEBUG: IW%.0f,%.0f,%.0f,%.0f = [ %.0f %.0f %.0f %.0f ]\n", + params[0].value.number, params[1].value.number, + params[2].value.number, params[3].value.number, + IW1[0], IW1[1], IW2[0], IW2[1]); + } + + + 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 : /* PS ; */ + if (Rotation == 0 || Rotation == 180) + { + PlotSize[0] = PageWidth; + PlotSize[1] = PageLength; + } + else + { + PlotSize[0] = PageLength; + PlotSize[1] = PageWidth; + } + break; + case 1 : /* PS length ; */ + 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 : /* PS length, width ; */ + /* + * Unfortunately, it appears that NO application correctly + * sends a two-argument PS command as documented in the + * HP-GL/2 Reference Manual from HP. Instead, applications + * send the width before the length, which causes all sorts + * of problems. + * + * Rather than fight it, we now look for them as width,length + * instead of length,width. + * + * Don't like it? Send mail to the folks that make Ideas, Pro/E, + * AutoCAD, etc. + */ + + if (Rotation == 0 || Rotation == 180) + { + PlotSize[0] = 72.0f * params[0].value.number / 1016.0f; + PlotSize[1] = 72.0f * params[1].value.number / 1016.0f; + } + else + { + PlotSize[0] = 72.0f * params[1].value.number / 1016.0f; + PlotSize[1] = 72.0f * params[0].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; + Scaling1[0] = P1[0]; + Scaling1[0] = P1[1]; + Scaling2[0] = P2[0]; + Scaling2[1] = P2[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 = 1; + } + + update_transform(); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/hpgl-input.c b/filter/hpgl-input.c new file mode 100644 index 0000000000..720122ee17 --- /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-2000 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, "%262143[^\"]\"", 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..cc3009e05e --- /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-2000 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 */ + 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 */ + + + 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); + + PPD = SetCommonOptions(num_options, options, 1); + + PlotSize[0] = PageWidth; + PlotSize[1] = PageLength; + + 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); + + 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..c6646a6e55 --- /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-2000 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..3b29f6dae2 --- /dev/null +++ b/filter/hpgl-prolog.c @@ -0,0 +1,373 @@ +/* + * "$Id$" + * + * HP-GL/2 prolog routines for for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 */ +{ + 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.1 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("%%Trailer"); + 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 */ + float iw1[2], iw2[2]; /* Clipping window */ + int i; /* Looping var */ + ppd_size_t *size; /* Page size */ + ppd_option_t *option; /* Page size option */ + ppd_choice_t *choice; /* Page size choice */ + float width, length; /* Page dimensions */ + int landscape; /* Rotate for landscape orientation? */ + + + /* + * Write the page header as needed... + */ + + if (!PageDirty) + { + PageDirty = 1; + PageCount ++; + + if (PPD != NULL && !FitPlot) + { + /* + * Set the page size for this page... + */ + + if (PageRotation == 0 || PageRotation == 180) + { + width = PlotSize[0]; + length = PlotSize[1]; + } + else + { + width = PlotSize[1]; + length = PlotSize[0]; + } + + landscape = 0; + + /* + * Lookup the closest PageSize and set it... + */ + + for (i = PPD->num_sizes, size = PPD->sizes; i > 0; i --, size ++) + if ((fabs(length - size->length) < 36.0 && size->width >= width) || + (fabs(length - size->width) < 36.0 && size->length >= width)) + break; + + if (i == 0 && PPD->variable_sizes) + { + for (i = PPD->num_sizes, size = PPD->sizes; i > 0; i --, size ++) + if (strcasecmp(size->name, "custom") == 0) + break; + } + + if (i > 0) + { + /* + * Found a matching size... + */ + + option = ppdFindOption(PPD, "PageSize"); + choice = ppdFindChoice(option, size->name); + + puts("%%BeginSetup"); + printf("%%%%BeginFeature: PageSize %s\n", size->name); + + if (strcasecmp(size->name, "custom") == 0) + { + PageLeft = PPD->custom_margins[0]; + PageRight = width - PPD->custom_margins[2]; + PageWidth = width; + PageBottom = PPD->custom_margins[1]; + PageTop = length - PPD->custom_margins[3]; + PageLength = length; + + printf("%.0f %.0f 0 0 0\n", width, length); + + if (choice->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... + */ + + puts("pop pop pop"); + puts("<>setpagedevice\n"); + } + else + { + /* + * Use the vendor-supplied command... + */ + + printf("%s\n", choice->code); + } + } + else + { + if (choice->code) + printf("%s\n", choice->code); + + if (fabs(length - size->width) < 36.0) + { + /* + * Do landscape orientation... + */ + + PageLeft = size->bottom; + PageRight = size->top; + PageWidth = size->length; + PageBottom = size->left; + PageTop = size->right; + PageLength = size->width; + + landscape = 1; + } + else + { + /* + * Do portrait orientation... + */ + + PageLeft = size->left; + PageRight = size->right; + PageWidth = size->width; + PageBottom = size->bottom; + PageTop = size->top; + PageLength = size->length; + } + } + + puts("%%EndFeature"); + puts("%%EndSetup"); + } + } + + printf("%%%%Page: %d %d\n", PageCount, PageCount); + + printf("/SA {\n" + " /%s%s%s%s findfont\n" + " [ %f %f %f %f 0.0 0.0 ] makefont\n" + " setfont\n" + "} bind def\n", + AlternateFont.typeface == 48 ? "Courier" : "Helvetica", + (AlternateFont.weight != 0 || AlternateFont.posture != 0) ? "-" : "", + AlternateFont.weight != 0 ? "Bold" : "", + AlternateFont.posture != 0 ? "Oblique" : "", + AlternateFont.x * AlternateFont.height, + -AlternateFont.y * AlternateFont.height, + AlternateFont.y * AlternateFont.height, + AlternateFont.x * AlternateFont.height); + + printf("/SS {\n" + " /%s%s%s%s findfont\n" + " [ %f %f %f %f 0.0 0.0 ] makefont\n" + " setfont\n" + "} bind def\n", + StandardFont.typeface == 48 ? "Courier" : "Helvetica", + (StandardFont.weight != 0 || StandardFont.posture != 0) ? "-" : "", + StandardFont.weight != 0 ? "Bold" : "", + StandardFont.posture != 0 ? "Oblique" : "", + StandardFont.x * StandardFont.height, + -StandardFont.y * StandardFont.height, + StandardFont.y * StandardFont.height, + StandardFont.x * StandardFont.height); + + if (CharFont) + puts("SA"); + else + puts("SS"); + + printf("%.1f setmiterlimit\n", MiterLimit); + printf("%d setlinecap\n", LineCap); + printf("%d setlinejoin\n", LineJoin); + + printf("%.3f %.3f %.3f %.2f SP\n", Pens[1].rgb[0], Pens[1].rgb[1], + Pens[1].rgb[2], Pens[1].width * PenScaling); + + puts("gsave"); + + if (Duplex && (PageCount & 1) == 0) + switch ((PageRotation / 90 + landscape) & 3) + { + case 0 : + printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom); + break; + case 1 : + printf("%.0f 0 translate 90 rotate\n", PageLength); + printf("%.1f %.1f translate\n", PageLength - PageTop, + PageWidth - PageRight); + break; + case 2 : + printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); + printf("%.1f %.1f translate\n", PageLeft, PageLength - PageTop); + break; + case 3 : + printf("0 %.0f translate -90 rotate\n", PageWidth); + printf("%.1f %.1f translate\n", PageBottom, PageLeft); + break; + } + else + switch ((PageRotation / 90 + landscape) & 3) + { + case 0 : + printf("%.1f %.1f translate\n", PageLeft, PageBottom); + break; + case 1 : + printf("%.0f 0 translate 90 rotate\n", PageLength); + printf("%.1f %.1f translate\n", PageBottom, PageWidth - PageRight); + break; + case 2 : + printf("%.0f %.0f translate 180 rotate\n", PageWidth, PageLength); + printf("%.1f %.1f translate\n", PageWidth - PageRight, + PageLength - PageTop); + break; + case 3 : + printf("0 %.0f translate -90 rotate\n", PageWidth); + printf("%.1f %.1f translate\n", PageLength - PageTop, PageLeft); + break; + } + + if (IW1[0] != IW2[0] && IW1[1] != IW2[1]) + { + iw1[0] = IW1[0] * 72.0f / 1016.0f; + iw1[1] = IW1[1] * 72.0f / 1016.0f; + iw2[0] = IW2[0] * 72.0f / 1016.0f; + iw2[1] = IW2[1] * 72.0f / 1016.0f; + + printf("initclip MP %.3f %.3f MO %.3f %.3f LI %.3f %.3f LI %.3f %.3f LI CP clip\n", + iw1[0], iw1[1], iw1[0], iw2[1], iw2[0], iw2[1], iw2[0], iw1[1]); + } + } + + /* + * 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..5b71629209 --- /dev/null +++ b/filter/hpgl-vector.c @@ -0,0 +1,707 @@ +/* + * "$Id$" + * + * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 ++; + PenNumber = (int)decode_number(&s, base_bits, 1.0); + if (PageDirty) + printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0], + Pens[PenNumber].rgb[PenNumber], Pens[PenNumber].rgb[2], + Pens[PenNumber].width * PenScaling); + 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..d1b65d2da9 --- /dev/null +++ b/filter/hpgltops.h @@ -0,0 +1,232 @@ +/* + * "$Id$" + * + * HP-GL/2 to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 + + +/* + * Font information... + */ + +typedef struct +{ + int typeface, /* Typeface number */ + posture, /* Posture number */ + weight; /* Weight number */ + float height; /* Height/size of font */ + float x, y; /* X and Y direction/scaling */ +} font_t; + + +/* + * Pen information... + */ + +typedef struct +{ + float rgb[3]; /* Pen color */ + float width; /* Pen width */ +} pen_t; + + +/* + * 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 ppd_file_t *PPD VALUE(NULL); /* PPD file */ + +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 font_t StandardFont, /* Standard font */ + AlternateFont; /* Alternate font */ +VAR float PenPosition[2] VALUE2(0.0f, 0.0f), + /* Current pen position */ + PenScaling VALUE(1.0f), /* Pen width scaling factor */ + PenWidth VALUE(1.0f); /* Default pen width */ +VAR pen_t Pens[1024]; /* State of each pen */ +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(0), /* 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_ */ +; + +VAR int LineCap VALUE(0); /* Line capping */ +VAR int LineJoin VALUE(0); /* Line joining */ +VAR float MiterLimit VALUE(3.0f); /* Miter limit at joints */ + + +/* + * 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); +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..1a42458be9 --- /dev/null +++ b/filter/image-colorspace.c @@ -0,0 +1,882 @@ +/* + * "$Id$" + * + * Colorspace conversions for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 */ + km; /* Maximum K value */ + 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)); + + if ((km = max(c, max(m, y))) > k) + k = k * k / km; + + c -= k; + m -= k; + y -= k; + + 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 ((km = max(c, max(m, y))) > k) + k = k * k / km; + + c -= k; + m -= k; + y -= k; + + *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..d1d5c6e977 --- /dev/null +++ b/filter/image-gif.c @@ -0,0 +1,644 @@ +/* + * "$Id$" + * + * GIF image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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..b352642b81 --- /dev/null +++ b/filter/image-jpeg.c @@ -0,0 +1,190 @@ +/* + * "$Id$" + * + * JPEG image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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..91eb05e3be --- /dev/null +++ b/filter/image-photocd.c @@ -0,0 +1,319 @@ +/* + * "$Id$" + * + * PhotoCD routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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..76be54c1d2 --- /dev/null +++ b/filter/image-png.c @@ -0,0 +1,205 @@ +/* + * "$Id$" + * + * PNG image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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..dbc956c61c --- /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-2000 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..1e8b2e2e57 --- /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-2000 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..ad8aa9e61a --- /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-2000 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..c6b6d9c22b --- /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-2000 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..7589c4f2c0 --- /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-2000 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..671828b663 --- /dev/null +++ b/filter/image-tiff.c @@ -0,0 +1,1621 @@ +/* + * "$Id$" + * + * TIFF file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 +# 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 = 128; + img->yppi = 128; + } + } + + /* + * 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..fe15632f1d --- /dev/null +++ b/filter/image-zoom.c @@ -0,0 +1,310 @@ +/* + * "$Id$" + * + * Image zoom routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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..ce0f470af0 --- /dev/null +++ b/filter/image.c @@ -0,0 +1,780 @@ +/* + * "$Id$" + * + * Base image support for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 +#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%254s", &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) + { + if (ic->next != NULL) + ic->next->prev = NULL; + + img->first = ic->next; + ic->next = NULL; + ic->prev = NULL; + } + else if (img->first == NULL) + img->first = ic; + + if (ic != img->last) + { + /* + * Remove the cache entry from the list... + */ + + if (ic->prev != NULL) + ic->prev->next = ic->next; + if (ic->next != NULL) + ic->next->prev = ic->prev; + + /* + * And add it to the end... + */ + + 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..74525c5216 --- /dev/null +++ b/filter/image.h @@ -0,0 +1,225 @@ +/* + * "$Id$" + * + * Image library definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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..0ac004f4ac --- /dev/null +++ b/filter/imagetops.c @@ -0,0 +1,564 @@ +/* + * "$Id$" + * + * Image file to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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, + xsize2, + ysize2; + 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); + + 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 = strcasecmp(val, "separate-documents-collated-copies") != 0; + } + + if ((val = cupsGetOption("Collate", num_options, options)) != NULL && + strcasecmp(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... + */ + + if (zoom == 0.0 && ppi == 0) + ppi = img->xppi; + + xprint = (PageRight - PageLeft) / 72.0; + yprint = (PageTop - PageBottom) / 72.0; + + 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; + + /* + * Rotate the image if it will fit landscape but not portrait... + */ + + if ((xinches > xprint || yinches > yprint) && + xinches <= yprint && yinches <= xprint) + { + /* + * Rotate the image as needed... + */ + + Orientation = (Orientation + 1) & 3; + xsize = yprint; + yprint = xprint; + xprint = xsize; + + xsize = PageLeft; + PageLeft = PageBottom; + PageBottom = PageWidth - PageRight; + PageRight = PageTop; + PageTop = PageLength - xsize; + + xsize = PageWidth; + PageWidth = PageLength; + PageLength = xsize; + } + } + 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; + } + + xsize2 = yprint * zoom; + ysize2 = xsize2 * img->ysize / img->xsize; + + if (ysize2 > (xprint * zoom)) + { + ysize2 = xprint * zoom; + xsize2 = ysize2 * img->xsize / img->ysize; + } + + /* + * Choose the rotation with the largest area, but prefer + * portrait if they are equal... + */ + + if ((xsize * ysize) < (xsize2 * xsize2)) + { + /* + * Do landscape orientation... + */ + + Orientation = 1; + xinches = xsize2; + yinches = ysize2; + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + + xsize = PageLeft; + PageLeft = PageBottom; + PageBottom = PageWidth - PageRight; + PageRight = PageTop; + PageTop = PageLength - xsize; + + xsize = PageWidth; + PageWidth = PageLength; + PageLength = xsize; + } + else + { + /* + * Do portrait orientation... + */ + + Orientation = 0; + 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? */ +{ + 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) + { + memset(data + length, 0, 4 - length); + b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3]; + + 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..4e148d2908 --- /dev/null +++ b/filter/imagetoraster.c @@ -0,0 +1,3972 @@ +/* + * "$Id$" + * + * Image file to raster filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 "raster.h" +#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, + xsize2, + ysize2; + 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 */ + ppd_profile_t userprofile; /* User-specified 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); + + 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 = strcasecmp(val, "separate-documents-collated-copies") != 0; + } + + if ((val = cupsGetOption("Collate", num_options, options)) != NULL && + strcasecmp(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, "CutMedia")) != NULL) + exec_choice(&header, choice); + + if ((choice = ppdFindMarkedChoice(ppd, "ESPFinishing")) != 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 ((val = cupsGetOption("profile", num_options, options)) != NULL) + { + profile = &userprofile; + sscanf(val, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", + &(userprofile.density), &(userprofile.gamma), + userprofile.matrix[0] + 0, userprofile.matrix[0] + 1, + userprofile.matrix[0] + 2, + userprofile.matrix[1] + 0, userprofile.matrix[1] + 1, + userprofile.matrix[1] + 2, + userprofile.matrix[2] + 0, userprofile.matrix[2] + 1, + userprofile.matrix[2] + 2); + + userprofile.density *= 0.001f; + userprofile.gamma *= 0.001f; + userprofile.matrix[0][0] *= 0.001f; + userprofile.matrix[0][1] *= 0.001f; + userprofile.matrix[0][2] *= 0.001f; + userprofile.matrix[1][0] *= 0.001f; + userprofile.matrix[1][1] *= 0.001f; + userprofile.matrix[1][2] *= 0.001f; + userprofile.matrix[2][0] *= 0.001f; + userprofile.matrix[2][1] *= 0.001f; + userprofile.matrix[2][2] *= 0.001f; + } + else 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) + profile = NULL; + } + + if (profile) + 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 (zoom == 0.0 && ppi == 0) + ppi = img->xppi; + + if (ppi > 0) + { + /* + * Scale the image as neccesary to match the desired pixels-per-inch. + */ + + if (Orientation & 1) + { + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + } + else + { + xprint = (PageRight - PageLeft) / 72.0; + yprint = (PageTop - PageBottom) / 72.0; + } + + xinches = (float)img->xsize / (float)ppi; + yinches = (float)img->ysize / (float)ppi; + + /* + * Rotate the image if it will fit landscape but not portrait... + */ + + if ((xinches > xprint || yinches > yprint) && + xinches <= yprint && yinches <= xprint) + { + /* + * Rotate the image as needed... + */ + + Orientation = (Orientation + 1) & 3; + xsize = yprint; + yprint = xprint; + xprint = xsize; + } + } + else + { + /* + * Scale percentage of page size... + */ + + xprint = (PageRight - PageLeft) / 72.0; + yprint = (PageTop - PageBottom) / 72.0; + + xsize = xprint * zoom; + ysize = xsize * img->ysize / img->xsize; + + if (ysize > (yprint * zoom)) + { + ysize = yprint * zoom; + xsize = ysize * img->xsize / img->ysize; + } + + xsize2 = yprint * zoom; + ysize2 = xsize2 * img->ysize / img->xsize; + + if (ysize2 > (xprint * zoom)) + { + ysize2 = xprint * zoom; + xsize2 = ysize2 * img->xsize / img->ysize; + } + + /* + * Choose the rotation with the largest area, but prefer + * portrait if they are equal... + */ + + if ((xsize * ysize) < (xsize2 * xsize2)) + { + /* + * Do landscape orientation... + */ + + Orientation = 1; + xinches = xsize2; + yinches = ysize2; + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + } + else + { + /* + * Do portrait orientation... + */ + + Orientation = 0; + xinches = xsize; + yinches = ysize; + } + } + + xpages = ceil(xinches / xprint); + ypages = ceil(yinches / yprint); + + /* + * Compute the bitmap size... + */ + + xprint = xinches / xpages; + yprint = yinches / ypages; + + if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL && + strcasecmp(choice->choice, "Custom") == 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; + } + + header.Margins[0] = PageLeft; + header.Margins[1] = PageBottom; + + switch (Orientation) + { + case 0 : + header.ImagingBoundingBox[0] = PageLeft; + header.ImagingBoundingBox[1] = PageBottom; + header.ImagingBoundingBox[2] = PageLeft + xprint * 72; + header.ImagingBoundingBox[3] = PageBottom + yprint * 72; + break; + case 1 : + header.ImagingBoundingBox[0] = PageRight - yprint * 72; + header.ImagingBoundingBox[1] = PageBottom; + header.ImagingBoundingBox[2] = PageRight; + header.ImagingBoundingBox[3] = PageBottom + xprint * 72; + break; + case 2 : + header.ImagingBoundingBox[0] = PageRight - xprint * 72; + header.ImagingBoundingBox[1] = PageTop - yprint * 72; + header.ImagingBoundingBox[2] = PageRight; + header.ImagingBoundingBox[3] = PageTop; + break; + case 3 : + header.ImagingBoundingBox[0] = PageLeft; + header.ImagingBoundingBox[1] = PageTop - xprint * 72; + header.ImagingBoundingBox[2] = PageLeft + yprint * 72 + 0.5f; + header.ImagingBoundingBox[3] = PageTop; + break; + } + + 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, "CutMedia") == 0) + header->CutMedia = (cups_cut_t)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) + strncpy(header->MediaType, value, sizeof(header->MediaType) - 1); + else if (strcmp(name, "OutputType") == 0) + strncpy(header->OutputType, value, sizeof(header->OutputType) - 1); + } +} + + +/* + * '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 / 3; + + 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 / 3; + + 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..afdcd232aa --- /dev/null +++ b/filter/pstops.c @@ -0,0 +1,867 @@ +/* + * "$Id$" + * + * PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 */ + int page_count; /* Page count for NUp */ + int subpage; /* Sub-page number */ + int copy; /* Current copy */ + + + 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]); + + options = NULL; + num_options = cupsParseOptions(argv[5], 0, &options); + + ppd = SetCommonOptions(num_options, options, 1); + + 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 = strcasecmp(val, "separate-documents-collated-copies") != 0; + } + + if ((val = cupsGetOption("Collate", num_options, options)) != NULL && + strcasecmp(val, "True") == 0) + Collate = 1; + + if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL && + strcasecmp(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 - 1)) == 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 (strcmp(line, "%%Trailer") == 0 && level == 0) + break; + 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 - 1); + + if (NumPages & (NUp - 1)) + { + start_nup(NUp - 1); + end_nup(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 - 1)) == 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); + } + + if (NumPages & (NUp - 1)) + { + start_nup(NUp - 1); + end_nup(NUp - 1); + } + + Copies --; + } + } + else + { + page_count = (NumPages + NUp - 1) / NUp; + copy = 0; + + do + { + for (page = page_count - 1; page >= 0; page --) + { + if (ppd == NULL || ppd->num_filters == 0) + fprintf(stderr, "PAGE: %d %d\n", page + 1, + slowcollate ? 1 : Copies); + + if (slowcollate) + printf("%%%%Page: %d %d\n", page + 1, + page_count - page + copy * page_count); + else + printf("%%%%Page: %d %d\n", page + 1, page_count - page); + + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + + for (subpage = 0, number = page * NUp; + subpage < NUp && number < NumPages; + subpage ++, number ++) + { + start_nup(number); + fseek(temp, Pages[number], SEEK_SET); + copy_bytes(temp, Pages[number + 1] - Pages[number]); + end_nup(number); + } + + if (number & (NUp - 1)) + { + start_nup(NUp - 1); + end_nup(NUp - 1); + } + } + + copy ++; + } + while (copy < Copies && slowcollate); + } + } + + /* + * Copy the trailer, if any... + */ + + while ((nbytes = fread(line, 1, sizeof(line), fp)) > 0) + fwrite(line, 1, nbytes, stdout); + } + 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 (strcasecmp(PageSet, "even") == 0 && (page & 1)) + return (0); + if (strcasecmp(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 (nleft > sizeof(buffer)) + nbytes = sizeof(buffer); + else + nbytes = nleft; + + if ((nbytes = fread(buffer, 1, nbytes, 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("ESPsave restore"); + + 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 */ + float pw, pl; /* Printable width and length of full page */ + + + if (Flip || Orientation || NUp > 1) + puts("/ESPsave save def"); + + if (Flip) + printf("%.0f 0 translate -1 1 scale\n", PageWidth); + + pw = PageRight - PageLeft; + pl = PageTop - PageBottom; + + 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 = pl; + l = w * PageLength / PageWidth; + + if (l > (pw * 0.5)) + { + l = pw * 0.5; + w = l * PageWidth / PageLength; + } + + tx = pw * 0.5 - l; + ty = (pl - w) * 0.5; + } + else + { + l = pw; + w = l * PageWidth / PageLength; + + if (w > (pl * 0.5)) + { + w = pl * 0.5; + l = w * PageLength / PageWidth; + } + + tx = pl * 0.5 - w; + ty = (pw - l) * 0.5; + } + + if (Duplex && (number & 2)) + printf("%.0f %.0f translate\n", PageWidth - PageRight, PageBottom); + else + printf("%.0f %.0f translate\n", PageLeft, PageBottom); + + if (Orientation & 1) + { + printf("0 %.0f translate -90 rotate\n", pl); + printf("%.0f %.0f translate %.3f %.3f scale\n", + ty, tx + l * x, w / pw, l / pl); + } + else + { + printf("%.0f 0 translate 90 rotate\n", pw); + printf("%.0f %.0f translate %.3f %.3f scale\n", + tx + w * x, ty, w / pw, l / pl); + } + + 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 = pw * 0.5; + l = w * PageLength / PageWidth; + + if (l > (pl * 0.5)) + { + l = pl * 0.5; + w = l * PageWidth / PageLength; + } + + if (Duplex && (number & 4)) + printf("%.0f %.0f translate\n", PageWidth - PageRight, PageBottom); + else + printf("%.0f %.0f translate\n", PageLeft, PageBottom); + + printf("%.0f %.0f translate %.3f %.3f scale\n", x * w, y * l, + 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; + } +} + + +/* + * End of "$Id$". + */ diff --git a/filter/raster.c b/filter/raster.c new file mode 100644 index 0000000000..be4f466234 --- /dev/null +++ b/filter/raster.c @@ -0,0 +1,252 @@ +/* + * "$Id$" + * + * Raster file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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/filter/raster.h b/filter/raster.h new file mode 100644 index 0000000000..2c4052d569 --- /dev/null +++ b/filter/raster.h @@ -0,0 +1,233 @@ +/* + * "$Id$" + * + * Raster file definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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/filter/rastertoepson.c b/filter/rastertoepson.c new file mode 100644 index 0000000000..3c2dd68b4c --- /dev/null +++ b/filter/rastertoepson.c @@ -0,0 +1,596 @@ +/* + * "$Id$" + * + * EPSON ESC/P and ESC/P2 filter for the Common UNIX Printing System + * (CUPS). + * + * Copyright 1993-2000 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: + * + * Setup() - Prepare the printer for printing. + * StartPage() - Start a page of graphics. + * EndPage() - Finish a page of graphics. + * Shutdown() - Shutdown the printer. + * CompressData() - Compress a line of graphics. + * OutputLine() - Output a line of graphics. + * main() - Main entry and processing of driver. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include "raster.h" +#include +#include +#include + + +/* + * Macros... + */ + +#define pwrite(s,n) fwrite((s), 1, (n), stdout) + + +/* + * Globals... + */ + +unsigned char *Planes[6], /* 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, ppd_file_t *ppd); +void EndPage(cups_page_header_t *header); +void Shutdown(void); + +void CompressData(unsigned char *line, int length, int plane, int type, + int xstep, int ystep); +void OutputLine(cups_page_header_t *header); + + +/* + * 'Setup()' - Prepare the printer for printing. + */ + +void +Setup(void) +{ + /* + * Send a reset sequence. + */ + + printf("\033@"); +} + + +/* + * 'StartPage()' - Start a page of graphics. + */ + +void +StartPage(cups_page_header_t *header, /* I - Page header */ + ppd_file_t *ppd) /* I - PPD file */ +{ + int n, t; /* Numbers */ + int plane; /* Looping var */ + + + /* + * Send a reset sequence. + */ + + printf("\033@"); + + /* + * Set graphics mode... + */ + + pwrite("\033(G\001\000\001", 6); /* Graphics mode */ + + /* + * Set the media size... + */ + + pwrite("\033(U\001\000", 5); /* Resolution/units */ + putchar(3600 / header->HWResolution[1]); + + n = header->PageSize[1] * header->HWResolution[1] / 72.0; + + pwrite("\033(C\002\000", 5); /* Page length */ + putchar(n); + putchar(n >> 8); + + t = (ppd->sizes[1].length - ppd->sizes[1].top) * + header->HWResolution[1] / 72.0; + + pwrite("\033(c\004\000", 5); /* Top & bottom margins */ + putchar(t); + putchar(t >> 8); + putchar(n); + putchar(n >> 8); + + /* + * Set other stuff... + */ + + if (header->cupsColorSpace == CUPS_CSPACE_CMY) + NumPlanes = 3; + else if (header->cupsColorSpace == CUPS_CSPACE_KCMY) + NumPlanes = 4; + else if (header->cupsColorSpace == CUPS_CSPACE_KCMYcm) + NumPlanes = 6; + else + NumPlanes = 1; + + if (header->HWResolution[1] == 720) + { + pwrite("\033(i\001\000\001", 6); /* Microweave */ + pwrite("\033(e\002\000\000\001", 7);/* Small dots */ + } + + pwrite("\033(V\002\000\000\000", 7); /* Set absolute position 0 */ + + 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... + */ + + putchar(12); /* Form feed */ + + /* + * Free memory... + */ + + free(Planes[0]); + + if (header->cupsCompression) + free(CompBuffer); +} + + +/* + * 'Shutdown()' - Shutdown the printer. + */ + +void +Shutdown(void) +{ + /* + * Send a reset sequence. + */ + + printf("\033@"); +} + + +/* + * '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 */ + int xstep, /* I - X resolution */ + int ystep) /* I - Y resolution */ +{ + 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 */ + temp; /* Current byte */ + int count; /* Count of bytes for output */ + static int ctable[6] = { 0, 2, 1, 4, 2, 1 }; + /* KCMYcm color values */ + + + /* + * Setup pointers... + */ + + line_ptr = line; + line_end = line + length; + + /* + * Do depletion for 720 DPI printing... + */ + + if (ystep == 5) + { + for (comp_ptr = line; comp_ptr < line_end;) + { + /* + * Grab the current byte... + */ + + temp = *comp_ptr; + + /* + * Check adjacent bits... + */ + + if ((temp & 0xc0) == 0xc0) + temp &= 0xbf; + if ((temp & 0x60) == 0x60) + temp &= 0xdf; + if ((temp & 0x30) == 0x30) + temp &= 0xef; + if ((temp & 0x18) == 0x18) + temp &= 0xf7; + if ((temp & 0x0c) == 0x0c) + temp &= 0xfb; + if ((temp & 0x06) == 0x06) + temp &= 0xfd; + if ((temp & 0x03) == 0x03) + temp &= 0xfe; + + *comp_ptr++ = temp; + + /* + * Check the last bit in the current byte and the first bit in the + * next byte... + */ + + if ((temp & 0x01) && comp_ptr < line_end && *comp_ptr & 0x80) + *comp_ptr &= 0x7f; + } + } + + switch (type) + { + case 0 : + /* + * Do no compression... + */ + break; + + case 1 : + /* + * Do TIFF pack-bits encoding... + */ + + 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 color if necessary... + */ + + if (NumPlanes > 1) + { + if (plane > 3) + printf("\033(r%c%c%c%c", 2, 0, 1, ctable[plane]); + /* Set extended color */ + else if (NumPlanes == 3) + printf("\033r%c", ctable[plane + 1]); + /* Set color */ + else + printf("\033r%c", ctable[plane]); /* Set color */ + } + + /* + * Send a raster plane... + */ + + putchar(0x0d); /* Move print head to left margin */ + + length *= 8; + printf("\033."); /* Raster graphics */ + putchar(type); + putchar(ystep); + putchar(xstep); + putchar(1); + putchar(length); + putchar(length >> 8); + + pwrite(line_ptr, line_end - line_ptr); +} + + +/* + * 'OutputLine()' - Output a line of graphics. + */ + +void +OutputLine(cups_page_header_t *header) /* I - Page header */ +{ + int plane; /* Current plane */ + int bytes; /* Bytes per plane */ + int xstep, ystep; /* X & Y resolutions */ + + /* + * Write bitmap data as needed... + */ + + xstep = 3600 / header->HWResolution[0]; + ystep = 3600 / header->HWResolution[1]; + bytes = header->cupsBytesPerLine / NumPlanes; + + for (plane = 0; plane < NumPlanes; plane ++) + { + /* + * Skip blank data... + */ + + if (!Planes[plane][0] && + memcmp(Planes[plane], Planes[plane] + 1, bytes - 1) == 0) + continue; + + /* + * Output whitespace as needed... + */ + + if (Feed > 0) + { + pwrite("\033(v\002\000", 5); /* Relative vertical position */ + putchar(Feed); + putchar(Feed >> 8); + + Feed = 0; + } + + CompressData(Planes[plane], bytes, plane, header->cupsCompression, xstep, + ystep); + } + + Feed ++; +} + + +/* + * '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 */ + ppd_file_t *ppd; /* PPD 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 return. + */ + + fputs("ERROR: rastertoepson job-id user title copies options [file]\n", stderr); + 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... + */ + + ppd = ppdOpenFile(getenv("PPD")); + + 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, ppd); + + /* + * 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; + + /* + * Write it to the printer... + */ + + OutputLine(&header); + } + + /* + * Eject the page... + */ + + EndPage(&header); + } + + /* + * Shutdown the printer... + */ + + Shutdown(); + + ppdClose(ppd); + + /* + * 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); + + return (page == 0); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/rastertohp.c b/filter/rastertohp.c new file mode 100644 index 0000000000..1365000896 --- /dev/null +++ b/filter/rastertohp.c @@ -0,0 +1,503 @@ +/* + * "$Id$" + * + * Hewlett-Packard Page Control Language filter for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1993-2000 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: + * + * Setup() - Prepare the printer for printing. + * StartPage() - Start a page of graphics. + * EndPage() - Finish a page of graphics. + * Shutdown() - Shutdown the printer. + * CompressData() - Compress a line of graphics. + * OutputLine() - Output a line of graphics. + * main() - Main entry and processing of driver. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "raster.h" +#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 return. + */ + + fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr); + 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); + + return (page == 0); +} + + +/* + * End of "$Id$". + */ diff --git a/filter/textcommon.c b/filter/textcommon.c new file mode 100644 index 0000000000..107c7b04df --- /dev/null +++ b/filter/textcommon.c @@ -0,0 +1,745 @@ +/* + * "$Id$" + * + * Common text filter routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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..354ce7ae5a --- /dev/null +++ b/filter/textcommon.h @@ -0,0 +1,93 @@ +/* + * "$Id$" + * + * Common text filter definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2000 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_NORMAL 0x00 +#define ATTR_BOLD 0x01 +#define ATTR_ITALIC 0x02 +#define ATTR_BOLDITALIC 0x03 +#define ATTR_FONT 0x03 + +#define ATTR_UNDERLINE 0x04 +#define ATTR_RAISED 0x08 +#define ATTR_LOWERED 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..e65f2c9c1c --- /dev/null +++ b/filter/texttops.c @@ -0,0 +1,1131 @@ +/* + * "$Id$" + * + * Text to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2000 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 */ +int NumFonts; /* Number of fonts to use */ +char *Fonts[256][4]; /* Fonts to use */ +unsigned short Chars[65536]; /* 0xffcc (ff = font, cc = char) */ +unsigned short Codes[65536]; /* Unicode glyph mapping to fonts */ +int Widths[256]; /* Widths of each font */ +int Directions[256];/* Text directions for each font */ + + +/* + * Local functions... + */ + +static void write_line(int row, lchar_t *line); +static void write_string(int col, int row, int len, lchar_t *s); +static void write_text(char *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 i, j, k; /* Looping vars */ + char *charset; /* Character set string */ + char filename[1024]; /* Glyph filenames */ + FILE *fp; /* Glyph files */ + char line[1024], /* Line from file */ + *lineptr, /* Pointer into line */ + *valptr; /* Pointer to value in line */ + int ch, unicode; /* Character values */ + int start, end; /* Start and end values for range */ + char glyph[64]; /* Glyph name */ + time_t curtime; /* Current time */ + struct tm *curtm; /* Current date */ + char curdate[255]; /* Current date (text format) */ + int num_fonts; /* Number of unique fonts */ + char *fonts[1024]; /* Unique fonts */ + static char *names[] = /* Font names */ + { + "cupsNormal", + "cupsBold", + "cupsItalic" + }; + + + /* + * Allocate memory for the page... + */ + + 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 (i = 1; i < SizeLines; i ++) + Page[i] = Page[0] + i * SizeColumns; + + if (PageColumns > 1) + { + ColumnGutter = CharsPerInch / 2; + ColumnWidth = (SizeColumns - ColumnGutter * (PageColumns - 1)) / + PageColumns; + } + else + ColumnWidth = SizeColumns; + + /* + * Output the DSC header... + */ + + 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); + puts("%%DocumentSuppliedResources: procset texttops 1.1 0"); + puts("%%Pages: (atend)"); + + /* + * Initialize globals... + */ + + NumFonts = 0; + memset(Fonts, 0, sizeof(Fonts)); + memset(Glyphs, 0, sizeof(Glyphs)); + memset(Chars, 0, sizeof(Chars)); + memset(Codes, 0, sizeof(Codes)); + + /* + * Load the PostScript glyph names and the corresponding character + * set definition... + */ + + if ((fp = fopen(CUPS_DATADIR "/data/psglyphs", "r")) != NULL) + { + while (fscanf(fp, "%x%63s", &unicode, glyph) == 2) + Glyphs[unicode] = strdup(glyph); + + fclose(fp); + } + else + { + perror("ERROR: Unable to open " CUPS_DATADIR "/data/psglyphs"); + exit(1); + } + + /* + * Get the output character set... + */ + + charset = getenv("CHARSET"); + if (charset != NULL && strcmp(charset, "us-ascii") != 0) + { + snprintf(filename, sizeof(filename), CUPS_DATADIR "/charsets/%s", charset); + + if ((fp = fopen(filename, "r")) == NULL) + { + /* + * Can't open charset file! + */ + + fprintf(stderr, "ERROR: Unable to open %s: %s\n", filename, + strerror(errno)); + exit(1); + } + + /* + * Opened charset file; now see if this is really a charset file... + */ + + if (fgets(line, sizeof(line), fp) == NULL) + { + /* + * Bad/empty charset file! + */ + + fclose(fp); + fprintf(stderr, "ERROR: Bad/empty charset file %s\n", filename); + exit(1); + } + + if (strncmp(line, "charset", 7) != 0) + { + /* + * Bad format/not a charset file! + */ + + fclose(fp); + fprintf(stderr, "ERROR: Bad charset file %s\n", filename); + exit(1); + } + + /* + * See if this is an 8-bit or UTF-8 character set file... + */ + + line[strlen(line) - 1] = '\0'; /* Drop \n */ + for (lineptr = line + 7; isspace(*lineptr); lineptr ++); /* Skip whitespace */ + + if (strcmp(lineptr, "8bit") == 0) + { + /* + * 8-bit text... + */ + + UTF8 = 0; + NumFonts = 1; + + /* + * Read the font description... + */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * Skip comment and blank lines... + */ + + if (line[0] != '#' && line[0] != '\n') + break; + } + + /* + * Read the font descriptions that should look like: + * + * direction width normal [bold italic bold-italic] + */ + + lineptr = line; + while (isspace(*lineptr)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + + if (!*lineptr) + { + /* + * Can't have a font without all required values... + */ + + fprintf(stderr, "ERROR: bad font description line: %s\n", valptr); + fclose(fp); + exit(1); + } + + *lineptr++ = '\0'; + + if (strcmp(valptr, "ltor") == 0) + Directions[0] = 1; + else if (strcmp(valptr, "rtol") == 0) + Directions[0] = -1; + else + { + fprintf(stderr, "ERROR: Bad text direction %s\n", valptr); + fclose(fp); + exit(1); + } + + /* + * Got the direction, now get the width... + */ + + while (isspace(*lineptr)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + + if (!*lineptr) + { + /* + * Can't have a font without all required values... + */ + + fprintf(stderr, "ERROR: bad font description line: %s\n", valptr); + fclose(fp); + exit(1); + } + + *lineptr++ = '\0'; + + if (strcmp(valptr, "single") == 0) + Widths[0] = 1; + else if (strcmp(valptr, "double") == 0) + Widths[0] = 2; + else + { + fprintf(stderr, "ERROR: Bad text width %s\n", valptr); + fclose(fp); + exit(1); + } + + /* + * Get the fonts... + */ + + for (i = 0; *lineptr && i < 4; i ++) + { + while (isspace(*lineptr)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + + if (*lineptr) + *lineptr++ = '\0'; + + if (lineptr > valptr) + Fonts[0][i] = strdup(valptr); + } + + /* + * Fill in remaining fonts as needed... + */ + + for (j = i; j < 4; j ++) + Fonts[0][j] = strdup(Fonts[0][0]); + + /* + * Read encoding lines... + */ + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * Skip comment and blank lines... + */ + + if (line[0] == '#' || line[0] == '\n') + continue; + + /* + * Grab the character and unicode glyph number. + */ + + if (sscanf(line, "%x%x", &ch, &unicode) == 2 && ch < 256) + { + Codes[ch] = unicode; + Chars[ch] = ch; + } + } + + fclose(fp); + } + else if (strcmp(lineptr, "utf8") == 0) + { + /* + * UTF-8 (Unicode) text... + */ + + UTF8 = 1; + + /* + * Read the font descriptions... + */ + + NumFonts = 0; + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * Skip comment and blank lines... + */ + + if (line[0] == '#' || line[0] == '\n') + continue; + + /* + * Read the font descriptions that should look like: + * + * start end direction width normal [bold italic bold-italic] + */ + + lineptr = line; + + start = strtol(lineptr, &lineptr, 16); + end = strtol(lineptr, &lineptr, 16); + + while (isspace(*lineptr)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + + if (!*lineptr) + { + /* + * Can't have a font without all required values... + */ + + fprintf(stderr, "ERROR: bad font description line: %s\n", valptr); + fclose(fp); + exit(1); + } + + *lineptr++ = '\0'; + + if (strcmp(valptr, "ltor") == 0) + Directions[NumFonts] = 1; + else if (strcmp(valptr, "rtol") == 0) + Directions[NumFonts] = -1; + else + { + fprintf(stderr, "ERROR: Bad text direction %s\n", valptr); + fclose(fp); + exit(1); + } + + /* + * Got the direction, now get the width... + */ + + while (isspace(*lineptr)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + + if (!*lineptr) + { + /* + * Can't have a font without all required values... + */ + + fprintf(stderr, "ERROR: bad font description line: %s\n", valptr); + fclose(fp); + exit(1); + } + + *lineptr++ = '\0'; + + if (strcmp(valptr, "single") == 0) + Widths[NumFonts] = 1; + else if (strcmp(valptr, "double") == 0) + Widths[NumFonts] = 2; + else + { + fprintf(stderr, "ERROR: Bad text width %s\n", valptr); + fclose(fp); + exit(1); + } + + /* + * Get the fonts... + */ + + for (i = 0; *lineptr && i < 4; i ++) + { + while (isspace(*lineptr)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr) && *lineptr) + lineptr ++; + + if (*lineptr) + *lineptr++ = '\0'; + + if (lineptr > valptr) + Fonts[NumFonts][i] = strdup(valptr); + } + + /* + * Fill in remaining fonts as needed... + */ + + for (j = i; j < 4; j ++) + Fonts[NumFonts][j] = strdup(Fonts[NumFonts][0]); + + /* + * Define the character mappings... + */ + + for (i = start, j = NumFonts * 256; i <= end; i ++, j ++) + { + Chars[i] = j; + Codes[j] = i; + } + + /* + * Move to the next font, stopping if needed... + */ + + NumFonts ++; + if (NumFonts >= 256) + break; + } + + fclose(fp); + } + else + { + fprintf(stderr, "ERROR: Bad charset type %s\n", lineptr); + fclose(fp); + exit(1); + } + } + else + { + /* + * Standard ASCII output just uses Courier, Courier-Bold, and + * possibly Courier-Oblique. + */ + + NumFonts = 1; + + Fonts[0][ATTR_NORMAL] = strdup("Courier"); + Fonts[0][ATTR_BOLD] = strdup("Courier-Bold"); + Fonts[0][ATTR_ITALIC] = strdup("Courier-Oblique"); + Fonts[0][ATTR_BOLDITALIC] = strdup("Courier-BoldOblique"); + + Widths[0] = 1; + Directions[0] = 1; + + /* + * Define US-ASCII characters... + */ + + for (i = 32; i < 127; i ++) + { + Chars[i] = i; + Codes[i] = i; + } + } + + /* + * Generate a list of unique fonts to use... + */ + + for (i = 0, num_fonts = 0; i < NumFonts; i ++) + for (j = 1 + PrettyPrint; j >= 0; j --) + { + for (k = 0; k < num_fonts; k ++) + if (strcmp(Fonts[i][j], fonts[k]) == 0) + break; + + if (k >= num_fonts) + { + /* + * Add new font... + */ + + fonts[num_fonts] = Fonts[i][j]; + num_fonts ++; + } + } + + /* + * List the fonts that will be used... + */ + + for (i = 0; i < num_fonts; i ++) + if (i == 0) + printf("%%DocumentNeededResources: font %s\n", fonts[i]); + else + printf("%%+ font %s\n", fonts[i]); + + puts("%%EndComments"); + + puts("%%BeginProlog"); + + /* + * Write the encoding array(s)... + */ + + puts("% character encoding(s)"); + + for (i = 0; i < NumFonts; i ++) + { + printf("/cupsEncoding%02x [\n", i); + + for (ch = 0; ch < 256; ch ++) + { + if (Glyphs[Codes[i * 256 + ch]]) + printf("/%s", Glyphs[Codes[i * 256 + ch]]); + else + printf("/.notdef"); + + if ((ch & 7) == 7) + putchar('\n'); + } + + puts("] def"); + } + + /* + * Create the fonts... + */ + + if (NumFonts == 1) + { + /* + * Just reencode the named fonts... + */ + + puts("% Reencode fonts"); + + for (i = 1 + PrettyPrint; i >= 0; i --) + { + printf("/%s findfont\n", Fonts[0][i]); + puts("dup length 1 add dict begin\n" + " { 1 index /FID ne { def } { pop pop } ifelse } forall\n" + " /Encoding cupsEncoding00 def\n" + " currentdict\n" + "end"); + printf("/%s exch definefont pop\n", names[i]); + } + } + else + { + /* + * Construct composite fonts... Start by reencoding the base fonts... + */ + + puts("% Reencode base fonts"); + + for (i = 1 + PrettyPrint; i >= 0; i --) + for (j = 0; j < NumFonts; j ++) + { + printf("/%s findfont\n", Fonts[j][i]); + printf("dup length 1 add dict begin\n" + " { 1 index /FID ne { def } { pop pop } ifelse } forall\n" + " /Encoding cupsEncoding%02x def\n" + " currentdict\n" + "end\n", j); + printf("/%s%02x exch definefont /%s%02x exch def\n", names[i], j, + names[i], j); + } + + /* + * Then merge them into composite fonts... + */ + + puts("% Create composite fonts..."); + + for (i = 1 + PrettyPrint; i >= 0; i --) + { + puts("8 dict begin"); + puts("/FontType 0 def/FontMatrix[1.0 0 0 1.0 0 0]def/FMapType 2 def/Encoding["); + for (j = 0; j < NumFonts; j ++) + if (j == (NumFonts - 1)) + printf("%d", j); + else if ((j & 15) == 15) + printf("%d\n", j); + else + printf("%d ", j); + puts("]def/FDepVector["); + for (j = 0; j < NumFonts; j ++) + if (j == (NumFonts - 1)) + printf("%s%02x", names[i], j); + else if ((j & 3) == 3) + printf("%s%02x\n", names[i], j); + else + printf("%s%02x ", names[i], j); + puts("]def currentdict end"); + printf("/%s exch definefont pop\n", names[i]); + } + } + + /* + * Output the texttops procset... + */ + + puts("%%BeginResource: procset texttops 1.1 0"); + + puts("% Define fonts"); + + printf("/FN /cupsNormal findfont [%.1f 0 0 %.1f 0 0] makefont def\n", + 120.0 / CharsPerInch, 68.0 / LinesPerInch); + printf("/FB /cupsBold findfont [%.1f 0 0 %.1f 0 0] makefont def\n", + 120.0 / CharsPerInch, 68.0 / LinesPerInch); + if (PrettyPrint) + printf("/FI /cupsItalic 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"); + printf("/U { gsave 0.5 setlinewidth 0 %.2f rmoveto " + "0 rlineto stroke grestore } bind def\n", -6.8 / LinesPerInch); + + 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("/n {"); + puts("\t20 string cvs % convert page number to string"); + puts("\tdup length % get length"); + puts("\tdup 2 mul string /P exch def % P = string twice as long"); + puts("\t0 1 2 index 1 sub { % loop through each character in the page number"); + puts("\t\tdup 3 index exch get % get character N from the page number"); + puts("\t\texch 2 mul dup % compute offset in P"); + puts("\t\tP exch 0 put % font 0"); + puts("\t\t1 add P exch 2 index put % character"); + puts("\t\tpop % discard character"); + puts("\t} for % do for loop"); + puts("\tpop pop % discard string and length"); + puts("\tP % put string on stack"); + puts("} bind def"); + + printf("/T"); + write_text(title); + puts("def"); + + printf("/D"); + write_text(curdate); + 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("\tD dup 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 n 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("\tn 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 */ + + + /**** TODO - handle bidi text and arabic composition ****/ + 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 ch; /* Current character */ + 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); + + if (UTF8) + { + /* + * Write a hex string... + */ + + putchar('<'); + + while (len > 0) + { + printf("%04x", Chars[s->ch]); + + len --; + s ++; + } + + putchar('>'); + } + else + { + /* + * Write a quoted string... + */ + + putchar('('); + + while (len > 0) + { + ch = Chars[s->ch]; + + if (ch < 32 || ch > 126) + { + /* + * Quote 8-bit and control characters... + */ + + printf("\\%03o", ch); + } + else + { + /* + * Quote the parenthesis and backslash as needed... + */ + + if (ch == '(' || ch == ')' || ch == '\\') + putchar('\\'); + + putchar(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"); +} + + +/* + * 'write_text()' - Write a text string, quoting/encoding as needed. + */ + +static void +write_text(char *s) /* I - String to write */ +{ + int ch; /* Actual character value (UTF8) */ + unsigned char *utf8; /* UTF8 text */ + + + if (UTF8) + { + /* + * 8/8 encoding... + */ + + putchar('<'); + + utf8 = (unsigned char *)s; + + while (*utf8) + { + if (*utf8 < 0xc0) + ch = *utf8 ++; + else if ((*utf8 & 0xe0) == 0xc0) + { + /* + * Two byte character... + */ + + ch = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f); + utf8 += 2; + } + else + { + /* + * Three byte character... + */ + + ch = ((((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)) << 6) | + (utf8[2] & 0x3f); + utf8 += 3; + } + + printf("%04x", Chars[ch]); + } + + putchar('>'); + } + else + { + /* + * Standard 8-bit encoding... + */ + + putchar('('); + + while (*s) + { + if (*s < 32 || *s > 126) + printf("\\%03o", *s); + else + { + if (*s == '(' || *s == ')' || *s == '\\') + putchar('\\'); + + putchar(*s); + } + + s ++; + } + + putchar(')'); + } +} + + +/* + * End of "$Id$". + */ diff --git a/fonts/AvantGarde-Book b/fonts/AvantGarde-Book new file mode 100644 index 0000000000..4d3a8b2ba7 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..c25c6ee4cc 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..67046dbe68 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..e0f6559e93 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..4e26c1cf52 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..6520e718dc 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..7cbac2c456 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..3ef45dcbec Binary files /dev/null and b/fonts/Bookman-LightItalic differ diff --git a/fonts/Charter-Bold b/fonts/Charter-Bold new file mode 100644 index 0000000000..0d82077ec4 Binary files /dev/null and b/fonts/Charter-Bold differ diff --git a/fonts/Charter-BoldItalic b/fonts/Charter-BoldItalic new file mode 100644 index 0000000000..c7a5f8798b Binary files /dev/null and b/fonts/Charter-BoldItalic differ diff --git a/fonts/Charter-Italic b/fonts/Charter-Italic new file mode 100644 index 0000000000..6abe1cdfdb Binary files /dev/null and b/fonts/Charter-Italic differ diff --git a/fonts/Charter-Roman b/fonts/Charter-Roman new file mode 100644 index 0000000000..b25133d510 Binary files /dev/null and b/fonts/Charter-Roman differ diff --git a/fonts/Courier b/fonts/Courier new file mode 100644 index 0000000000..0cadce7d13 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..f1da6121bb 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..8b7c24ff3a 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..107a513372 Binary files /dev/null and b/fonts/Courier-Oblique differ diff --git a/fonts/Helvetica b/fonts/Helvetica new file mode 100644 index 0000000000..ff605552c9 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..aec380a331 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..479904083a 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..f2387225df 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..7ee6a2c812 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..d2e96f3b7e 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..4ff13e5f64 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..876cda876d Binary files /dev/null and b/fonts/Helvetica-Oblique differ diff --git a/fonts/Makefile b/fonts/Makefile new file mode 100644 index 0000000000..fdf8ee8efa --- /dev/null +++ b/fonts/Makefile @@ -0,0 +1,73 @@ +# +# "$Id$" +# +# Fonts makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2000 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 Charter-Bold \ + Charter-BoldItalic Charter-Italic Charter-Roman 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..321a282f43 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..31e589003a 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..2fbd616479 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..6cbded3c76 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..7f5df43f3d 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..1c812b8391 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..8d0f820de1 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..4101b73358 Binary files /dev/null and b/fonts/Palatino-Roman differ diff --git a/fonts/Symbol b/fonts/Symbol new file mode 100644 index 0000000000..d0505e46cd 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..47f8fd57da 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..2d19d942ea 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..aa9ff5f8ac 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..cbae7ed157 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..28443517d3 Binary files /dev/null and b/fonts/ZapfChancery-MediumItalic differ diff --git a/fonts/ZapfDingbats b/fonts/ZapfDingbats new file mode 100644 index 0000000000..4a3c386d29 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..e4654b1f28 --- /dev/null +++ b/locale/C/cups_C @@ -0,0 +1,132 @@ +us-ascii +OK +Cancel +Help +Quit +Close +Yes +No +On +Off +Save +Discard +Default +Options +More Info +Black +Color +Cyan +Magenta +Yellow +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +General +Printer +Image +HP-GL/2 +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 +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 +Text +Pretty Print +Margins +Left +Right +Bottom +Top +Filename(s) +Print +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..639e50da82 --- /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) $$dir/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..f6f699a3ae --- /dev/null +++ b/locale/de/cups_de @@ -0,0 +1,133 @@ +iso-8859-1 +Okay +Abbrechen +Hilfe +Beenden +Schließen +Ja +Nein +An +Aus +Speichern +Verwerfen +Default +Optionen +Mehr Info +Schwarz +Farbe +Cyan +Magenta +Gelb +Copyright 1993-2000 durch Easy Software Products, alle Rechte vorbehalten. +Allgemein +Drucker +Bild +HP-GL/2 +Speziell +Dokument +Andere +Druckbereich: +Gesamtes Dokument +Seitenbereich: +Umgedrehte Reihenfolge: +Seitenformat: + normal + 2 auf 1 + 4 auf 1 +Bild-Skalierung: +Natürliche Bildgröße +Zoom in Prozent +Zoom in PPI +Gespiegelte Ausgabe: +Farbsättigung: +Farbton: +Auf Seite anpassen: +Schattiert: +Strichstärke: +Gamma-Korrektur: +Helligkeit: +Hinzufügen +Löschen +Ändern +Drucker-URI +Drucker-Name +Drucker-Standort +Drucker-Info +Drucker-Modell +Device-URI +Formatiere Seite +Drucke Seite +Initialisiere Drucker +Drucker-Zustand +Bereit +Nicht bereit +Druckaufträge +Klasse +Lokal +Remote +Duplex +Hefter +Schnellkopien +Sortieren/Gruppieren +Locher +Deckblatt +Bindung +Sortieren +Klein (bis 14x35cm) +Medium (14x35cm bis 33x48cm) +Groß (33x48cm und größer) +Benutzerspezifische Größe +Leerlauf +In Arbeit +Gestoppt +Alles +Ungerade +Gerade +Dunkler Heller +Medien-Größe +Medium +Medien-Quelle +Ausrichtung: +Hochformat +Querformat +Job-Status +Job-Name +Benutzername +Priorität +Kopien +Dateigröße +In Warteposition +Ausgabe-Modus +Auflösung +Text +Spezieller Druck +Seitenränder +Links +Recht +Unterseite +Oberseite +Dateiname(s) +Druker +400 Der Server versteht die Anfrage Ihres Browsers nicht. +Der Server konnte nicht Ihre Berechtigung überprüfen, diese Ressource zu benutzen. +Sie müssen bezahlen, um auf diesen Server zuzugreifen. +Sie sind nicht berechtigt, auf diese Ressource des Servers zuzugreifen. +Die gewünschte Ressource wurde auf diesem Server nicht gefunden. +Die gewünschte Methode ist mit dieser Ressource nicht erlaubt. +Eine passende Art der Ressource wurde auf diesem Server nicht gefunden. +Sie können diesen Server nicht als Proxy-Server verwenden. +Der Auftrag brauchte zu lang zur Beendigung und wurde abgebrochen. +Die gewünschte Ressource besitzt mehr als einen Wert. +Die gewünschte Ressource existiert nicht mehr und wurde nicht ersetzt. +Die gewünschte Methode benötigt eine gültige Länge des Inhalts. +Die Voraussetzungen für den Auftrag sind nicht erfüllt. +Der Auftrag ist zu groß, um auf diesem Server verarbeitet zu werden. +Die URI des Auftrags ist zu groß, um auf diesem Server verarbeitet zu werden. +Das Format des Auftrags wird von diesem Server nicht verstanden. +500 Der Server hat einen nicht behebbaren Fehler entdeckt und kann Ihren Auftrag nicht verarbeiten. +Die gewünschte Methode ist auf diesen Server nicht implementiert. +Der Proxy-Server empfing eine unzulässige Antwort von einem höheren Server. +Die gewünschte Ressource ist aktuell auf diesem Server nicht verfügbarr. +Der Proxy-Server braucht zu lang, um auf diesen Server zu reagieren. +Dieser Server unterstützt nicht die HTTP-Version, die Ihr Browser benötigt. + diff --git a/locale/en/cups_en b/locale/en/cups_en new file mode 100644 index 0000000000..35d291a176 --- /dev/null +++ b/locale/en/cups_en @@ -0,0 +1,132 @@ +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-2000 by Easy Software Products, All Rights Reserved. +General +Printer +Image +HP-GL/2 +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 +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 +Text +Pretty Print +Margins +Left +Right +Bottom +Top +Filename(s) +Print +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..c9c3420cc8 --- /dev/null +++ b/locale/es/cups_es @@ -0,0 +1,132 @@ +iso-8859-1 +OK +Cancel +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-2000 por Easy Software Products, todos endereza reservado. +General +Impresora +Imagen +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 +Par +Más Oscuro Más Brillante +Talla De Media +Tipo De Media +Fuente De los Media +Orientación: +Retrato +Paisaje +Estatus del trabajo +Nombre del trabajo +Nombre del utilizador +Prioridad +Copias +Tamaño +Pendiente +Modo de impresión +Resolución +Texto +Especial impresión +Márgenes +Izquierda +La derecha +Fondo +Tapa +Nombre(s) +Impresión +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..542749347c --- /dev/null +++ b/locale/fr/cups_fr @@ -0,0 +1,132 @@ +iso-8859-1 +OK +Annulation +Aide +Quitté +Fermer +Oui +Non +Oui +Non +Sauver +Quitté +Défaut +Options +Plus d'information +Noir +Couleur +Cyan +Magenta +Jaune +Copyright 1993-2000 par Easy Software Products, tous droits réservés. +Général +Imprimante +Image +HP-GL/2 +Options supplémentaires +Document +Autre +Pages d'impression: +Entier document +Chaîne de page +Commande d'Inversion: +Pages par feuilles: + 1 + 2 + 4 +Graduation d'image: +Emploi taille normale d'image +Zoom par pourcent +Zoom par PPI +Image de miroir: +Saturation de couleur: +Teinture de couleur: +Correspondre au page: +Ombrageant: +Largeur de crayon lecteur: +Correction de Gamma: +Éclat: +Ajoutez +Éffacer +Modifiez +URI de l'imprimante +Nom de l'imprimante +Emplacement de l'imprimante +Information de l'imprimante +Font et modèlent de l'imprimante +Dispositif de l'URI +Formatage du page +Imprimant la page +Initialisation de l'imprimante +État de l'Imprimante +Recevant les travaux +Ne recevant pas Les Travaux +Tirages +Classe +Local +Distant +Duplexage +Agrafant +Copie Rapides +Copies Assemblées +Poinçon de trou +Bâche +Liant +Triant +Petit (jusqu'à 9.5x1pouce) +Moyen (9.5x1pouce à 13x19pouce) +Grand (13x19pouce et plus grand) +Taille faite sur commande +Arrêter +Traitant +Arrêté +Tout +Impair +Même +Plus foncé Plus Lumineux +Dimension du medias +Sorte de medias +Source du medias +Orientation: +Verticale +Horizontal +État du travail +Nom du travail +Nom de l'utilisateur +Priorité +Copies +Grandeur du fichier +Imminent +Method de sortie +Resolution +Texte +Empreinte Spéciale +Marge +Gauche +Droite +Bas +Haut +Nom du ficher(s) +Imprimer +400 Votre browser a envoyé une demande que ce serveur ne pouvait pas comprendre. +Ce serveur ne pouvait pas vérifier que vous êtes autoriséz à 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 ce serveur. +L'Uri de demande est trop grand pour ce serveur. +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 actuellement 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..29e7725b09 --- /dev/null +++ b/locale/it/cups_it @@ -0,0 +1,132 @@ +iso-8859-1 +Procedi +Annulla +Aiuto +Esci +Chiudi +Sì +No +Attivo +Inattivo +Salva +Scarta +Standard +Opzioni +Più Informazioni +Nero +Colore +Ciano +Fucsia +Giallo +Copyright 1993-2000 di Easy Software Products, tutti i diritti riservati. +Generale +Stampante +Immagini +HP-GL/2 +Extra +Documento +Altro +Stampa delle pagine: +Intero Documento +Stampa intervallo: +Ordine inverso: +Formato della pagina: + 1-Up + 2-Up + 4-Up +Scaling dell'immagine: +Usa formato naturale dell'immagine +Zoom in percentuale +Zoom in PPI +Immagine riflessa: +Saturazione del colore: +Tonalità del colore: +Adatta alla pagina: +Ombreggiatura: +Larghezza della penna: +Correzione Gamma: +Luminosità: +Aggiungi +Cancella +Modifica +URI della stampante +Nome della stampante +Collocazione della stampante +Informazioni sulla stampante +Produttore e modello della stampante +URI Del Dispositivo +Preparazione della pagina +Stampa della Pagina +Inizializzazione Stampante +Condizione della stampante +Sto accettando le richieste di stampa +Non sto accettando le richieste di stampa +Richieste di stampa +Codice categoria +Locale +Remoto +Fronte-retro +Sto cucendo con punti metallici +Copie veloci +Copie fascicolate +Perforazione delle pagine (per fascicolatura) +Inserendo copertina +Applicando fascicolatura +Ordinando +Piccolo (fino a 9.5x1în) +Medio (9.5x1în - 13x19in) +Grande (13x19in e più grande) +Formato personalizzato +Idle +Elaborando +Arrestato +Tutto +Dispari +Pari +Più Scuro Più Luminoso +Formato del supporto +Tipo del supporto +Sorgente del supporto +Orientamento: +Verticale +Orizzontale +Condizione di lavoro +Nome di lavoro +Nome dell' utente +Priorita' +Copie +Dimensioni del file +In attesa +Modo stampa +Risoluzione +Testo +Speciale stampa +Margini +Sinistra +Destra +Inferiore +Superiore +Nome(s) +Stampa +400 Il vostro browser ha trasmesso una richiesta che questo server non ha capito +Questo server non ha potuto verificare che siete autorizzati ad accedere alla risorsa. +Dovete pagare accedere a questo server. +Non avete il permesso di accedere alla risorsa richiesta su questo server. +La risorsa chiesta non è stata trovata su questo server. +Il metodo richiesto non è consentito con la risorsa desiderata. +Una rappresentazione adatta per la risorsa non è stata trovata su questo server. +Non avete il permesso utilizzare questo server come proxy. +La richiesta ha impiegato troppo tempo per essere completata ed è stata abbandonata. +La risorsa chiesta ha più di un valore. +La risorsa chiesta non e' piu' disponibile e non è stata ancora rimpiazzata. +Il metodo chiesto richiede un campo "Content-Length" valido. +I prerequisiti per la richiesta non sono soddisfatti. +La richiesta è troppo grande per essere elaborata da questo server. +L'URI della richiesta è troppo grande per essere elaborato da questo server. +Il formato della richiesta non è capito da questo server. +500 Il server ha rilevato un errore non recuperabile e non può elaborare la vostra richiesta. +Il metodo chiesto non è implementato da questo server. +Il proxy server ha ricevuto una risposta non valida da un server di livello superiore. +La risorsa chiesta è attualmente non disponibile su questo server. +Il proxy server ha impiegato troppo tempo per rispondere a questo server. +Questo server non supporta la versione 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..7d7dcab823 --- /dev/null +++ b/man/Makefile @@ -0,0 +1,93 @@ +# +# "$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... +# + +CAT1 = backend.1 filter.1 lp.1 lpq.1 lprm.1 lpr.1 lpstat.1 +CAT5 = classes.conf.5 cupsd.conf.5 mime.convs.5 mime.types.5 \ + printers.conf.5 +CAT8 = accept.8 cupsd.8 enable.8 lpadmin.8 lpc.8 + +MAN1 = $(CAT1:.1=.man) +MAN5 = $(CAT5:.5=.man) +MAN8 = $(CAT8:.8=.man) + + +# +# Make everything... +# + +all: $(CAT1) $(CAT5) $(CAT8) + + +# +# Clean all config and object files... +# + +clean: + + +# +# Install files... +# + +install: + -$(MKDIR) $(MANDIR)/man1 + for file in $(MAN1); do \ + $(CP) $$file $(MANDIR)/man1/`basename $$file man`1; \ + done + $(RM) $(MANDIR)/man1/cancel.1 + $(LN) lp.1 $(MANDIR)/man1/cancel.1 + -$(MKDIR) $(MANDIR)/cat1 + $(CP) $(CAT1) $(MANDIR)/cat1 + $(RM) $(MANDIR)/cat1/cancel.1 + $(LN) lp.1 $(MANDIR)/cat1/cancel.1 + -$(MKDIR) $(MANDIR)/man5 + for file in $(MAN5); do \ + $(CP) $$file $(MANDIR)/man5/`basename $$file man`5; \ + done + -$(MKDIR) $(MANDIR)/cat5 + $(CP) $(CAT5) $(MANDIR)/cat5 + -$(MKDIR) $(MANDIR)/man8 + for file in $(MAN8); do \ + $(CP) $$file $(MANDIR)/man8/`basename $$file man`8; \ + done + $(RM) $(MANDIR)/man8/reject.8 + $(LN) accept.8 $(MANDIR)/man8/reject.8 + $(RM) $(MANDIR)/man8/disable.8 + $(LN) enable.8 $(MANDIR)/man8/disable.8 + -$(MKDIR) $(MANDIR)/cat8 + $(CP) $(CAT8) $(MANDIR)/cat8 + $(RM) $(MANDIR)/cat8/reject.8 + $(LN) accept.8 $(MANDIR)/cat8/reject.8 + $(RM) $(MANDIR)/cat8/disable.8 + $(LN) enable.8 $(MANDIR)/cat8/disable.8 + +# +# End of "$Id$". +# diff --git a/man/accept.8 b/man/accept.8 new file mode 100644 index 0000000000..4a7831efcb --- /dev/null +++ b/man/accept.8 @@ -0,0 +1,66 @@ + + + +accept(8) Easy Software Products accept(8) + + +NNAAMMEE + accept/reject - accept/reject jobs sent to a destination + +SSYYNNOOPPSSIISS + aacccceepptt destination(s) + rreejjeecctt [ -h _s_e_r_v_e_r ] [ -r [ _r_e_a_s_o_n ] ] destination(s) + +DDEESSCCRRIIPPTTIIOONN + _a_c_c_e_p_t instructs the printing system to accept print jobs + to the specified destinations. + + _r_e_j_e_c_t instructs the printing system to reject print jobs + to the specified destinations. The _-_r option sets the rea- + son for rejecting print jobs. If not specified the reason + defaults to "Reason Unknown". + +CCOOMMPPAATTIIBBIILLIITTYY + The CUPS versions of _a_c_c_e_p_t and _r_e_j_e_c_t 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. + +SSEEEE AALLSSOO + cancel(1), disable(8), enable(8), lp(1), lpadmin(8), + lpstat(1), CUPS Software Administrators Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/accept.man b/man/accept.man new file mode 100644 index 0000000000..0e4b6e47d0 --- /dev/null +++ b/man/accept.man @@ -0,0 +1,57 @@ +.\" +.\" "$Id: accept.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" accept/reject man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 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 +\fIaccept\fR instructs the printing system to accept print jobs to the +specified destinations. +.LP +\fIreject\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 \fIaccept\fR and \fIreject\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 Administrators Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: accept.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/backend.1 b/man/backend.1 new file mode 100644 index 0000000000..161cbf8655 --- /dev/null +++ b/man/backend.1 @@ -0,0 +1,132 @@ + + + +backend(1) Easy Software Products backend(1) + + +NNAAMMEE + backend - backend transmission interfaces + +SSYYNNOOPPSSIISS + bbaacckkeenndd job user title num-copies options _[ _f_i_l_e_n_a_m_e _] + +DDEESSCCRRIIPPTTIIOONN + The CUPS backend interface provides a standard method for + sending document files to different physical interfaces. + + 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. + + The command name (argv[0]) is set to the device URI of the + destination printer. + +EENNVVIIRROONNMMEENNTT VVAARRIIAABBLLEESS + The following environment variables are defined by the + CUPS server when executing the backend: + + CHARSET + The default text character set (typically us-ascii or + iso-8859-1). + + CONTENT_TYPE + The MIME type associated with the file (e.g. applica- + tion/postscript). + + DEVICE_URI + The device-uri associated with the printer; this is + provided for shell scripts which may not be able to + get the passed argv[0] string. + + LANG + The default language locale (typically C or en). + + PATH + The standard execution path for external programs + that may be run by the backend. + + PPD + The full pathname of the PostScript Printer Descrip- + tion (PPD) file for this printer. + + PRINTER + The name of the printer. + + RIP_CACHE + The recommended amount of memory to use for Raster + Image Processors (RIPs). + + SERVER_ROOT + The root directory of the server. + + + +22 September 1999 Common UNIX Printing System 1 + + + + + +backend(1) Easy Software Products backend(1) + + + SOFTWARE + The name and version number of the server (typically + CUPS/1.0). + + TZ + The timezone of the server. + + USER + The user executing the backend (typically lp). + +SSEEEE AALLSSOO + cupsd(8), filter(1) CUPS Software Administrators Manual, + CUPS Interface Design Description + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 2 + + diff --git a/man/backend.man b/man/backend.man new file mode 100644 index 0000000000..dcee092880 --- /dev/null +++ b/man/backend.man @@ -0,0 +1,102 @@ +.\" +.\" "$Id: backend.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" backend man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 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 +CONTENT_TYPE +.br +The MIME type associated with the file (e.g. application/postscript). +.TP 5 +DEVICE_URI +.br +The device-uri associated with the printer; this is provided for shell +scripts which may not be able to get the passed argv[0] string. +.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 +PRINTER +.br +The name of the 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. +.TP 5 +USER +.br +The user executing the backend (typically lp). +.SH SEE ALSO +cupsd(8), filter(1) +CUPS Software Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: backend.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/classes.conf.5 b/man/classes.conf.5 new file mode 100644 index 0000000000..53b8945e4e --- /dev/null +++ b/man/classes.conf.5 @@ -0,0 +1,66 @@ + + + +classes.conf(5) Easy Software Products classes.conf(5) + + +NNAAMMEE + classes.conf - class configuration file for cups + +DDEESSCCRRIIPPTTIIOONN + The _c_l_a_s_s_e_s_._c_o_n_f file defines the local printer classes + that are available. It is normally generated by the + _c_u_p_s_d_(_8_) program when printer classes are added or + deleted. + +SSEEEE AALLSSOO + cupsd(8), cupsd.conf(5), mime.convs(5), mime.types(5), + printers.conf(5), CUPS Software Administrators Manual, + CUPS Interface Design Description + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/classes.conf.man b/man/classes.conf.man new file mode 100644 index 0000000000..74d8a183a6 --- /dev/null +++ b/man/classes.conf.man @@ -0,0 +1,39 @@ +.\" +.\" "$Id: classes.conf.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" classes.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +classes.conf \- class configuration file for cups +.SH DESCRIPTION +The \fIclasses.conf\fR file defines the local printer classes that are +available. It is normally generated by the \fIcupsd(8)\fR program when +printer classes are added or deleted. +.SH SEE ALSO +cupsd(8), cupsd.conf(5), mime.convs(5), mime.types(5), printers.conf(5), +CUPS Software Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: classes.conf.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/cupsd.8 b/man/cupsd.8 new file mode 100644 index 0000000000..8c2c15eeb9 --- /dev/null +++ b/man/cupsd.8 @@ -0,0 +1,66 @@ + + + +cupsd(8) Easy Software Products cupsd(8) + + +NNAAMMEE + cupsd - common unix printing system daemon + +SSYYNNOOPPSSIISS + ccuuppssdd _[ _-_c _c_o_n_f_i_g_-_f_i_l_e _] + +DDEESSCCRRIIPPTTIIOONN + _c_u_p_s_d is the scheduler for the Common UNIX Printing Sys- + tem. It implements a printing system based upon the Inter- + net Printing Protocol, version 1.0. If no options are + specified on the command-line then the default configura- + tion file (usually _/_v_a_r_/_c_u_p_s_/_c_o_n_f_/_c_u_p_s_d_._c_o_n_f) will be + used. + +CCOOMMPPAATTIIBBIILLIITTYY + _c_u_p_s_d implements all of the required IPP/1.0 attributes + and operations. It also implements optional operation set + 1 and several CUPS-specific administation operations. + +SSEEEE AALLSSOO + backend(1), classes.conf(5), cupsd.conf(5), filter(1), + mime.convs(5), mime.types(5), printers.conf(5), CUPS Soft- + ware Administrators Manual, CUPS Interface Design Descrip- + tion + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/cupsd.conf.5 b/man/cupsd.conf.5 new file mode 100644 index 0000000000..da09c6d2ec --- /dev/null +++ b/man/cupsd.conf.5 @@ -0,0 +1,66 @@ + + + +cupsd.conf(5) Easy Software Products cupsd.conf(5) + + +NNAAMMEE + cupsd.conf - server configuration file for cups + +DDEESSCCRRIIPPTTIIOONN + The _c_u_p_s_d_._c_o_n_f file configures the CUPS scheduler, + _c_u_p_s_d_(_8_). + +SSEEEE AALLSSOO + classes.conf(5), cupsd(8), mime.convs(5), mime.types(5), + printers.conf(5), CUPS Software Administrators Manual, + CUPS Interface Design Description + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/cupsd.conf.man b/man/cupsd.conf.man new file mode 100644 index 0000000000..5c1ecf59ca --- /dev/null +++ b/man/cupsd.conf.man @@ -0,0 +1,37 @@ +.\" +.\" "$Id: cupsd.conf.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" cupsd.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +cupsd.conf \- server configuration file for cups +.SH DESCRIPTION +The \fIcupsd.conf\fR file configures the CUPS scheduler, \fIcupsd(8)\fR. +.SH SEE ALSO +classes.conf(5), cupsd(8), mime.convs(5), mime.types(5), printers.conf(5), +CUPS Software Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupsd.conf.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/cupsd.man b/man/cupsd.man new file mode 100644 index 0000000000..4b5616b3d6 --- /dev/null +++ b/man/cupsd.man @@ -0,0 +1,48 @@ +.\" +.\" "$Id: cupsd.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" cupsd man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +cupsd \- common unix printing system daemon +.SH SYNOPSIS +.B cupsd +.I [ \-c config-file ] +.SH DESCRIPTION +\fIcupsd\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/cupsd.conf\fR) will be used. +.SH COMPATIBILITY +\fIcupsd\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 +backend(1), classes.conf(5), cupsd.conf(5), filter(1), mime.convs(5), +mime.types(5), printers.conf(5), +CUPS Software Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupsd.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/enable.8 b/man/enable.8 new file mode 100644 index 0000000000..dbf4a587d4 --- /dev/null +++ b/man/enable.8 @@ -0,0 +1,66 @@ + + + +enable(8) Easy Software Products enable(8) + + +NNAAMMEE + disable, enable - stop/start printers and classes + +SSYYNNOOPPSSIISS + ddiissaabbllee [ -c ] [ -h _s_e_r_v_e_r ] [ -r [ _r_e_a_s_o_n ] ] destina- + tion(s) + eennaabbllee destination(s) + +DDEESSCCRRIIPPTTIIOONN + _e_n_a_b_l_e starts the named printers or classes. + + _d_i_s_a_b_l_e stops the named printers or classes. The follow- + ing options may be used: + + -c + Cancels all jobs on the named destination. + + -r [ _r_e_a_s_o_n ] + Sets the message associated with the stopped state. + If no reason is specified then the message is set to + "Reason Unknown". + +CCOOMMPPAATTIIBBIILLIITTYY + The CUPS versions of _d_i_s_a_b_l_e and _e_n_a_b_l_e 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. + +SSEEEE AALLSSOO + accept(8), cancel(1), lp(1), lpadmin(8), lpstat(1), + reject(8), CUPS Software Administrators Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/enable.man b/man/enable.man new file mode 100644 index 0000000000..fd9e3b881e --- /dev/null +++ b/man/enable.man @@ -0,0 +1,64 @@ +.\" +.\" "$Id: enable.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" enable/disable man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +disable, enable \- stop/start printers and classes +.SH SYNOPSIS +.B disable +[ \-c ] [ -h +.I server +] [ \-r [ +.I reason +] ] destination(s) +.br +.B enable +destination(s) +.SH DESCRIPTION +\fIenable\fR starts the named printers or classes. +.LP +\fIdisable\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 \fIdisable\fR and \fIenable\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 Administrators Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. + +.\" +.\" End of "$Id: enable.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/filter.1 b/man/filter.1 new file mode 100644 index 0000000000..d6d3cb8567 --- /dev/null +++ b/man/filter.1 @@ -0,0 +1,132 @@ + + + +filter(1) Easy Software Products filter(1) + + +NNAAMMEE + filter - file conversion filter interfaces + +SSYYNNOOPPSSIISS + ffiilltteerr job user title num-copies options _[ _f_i_l_e_n_a_m_e _] + +DDEESSCCRRIIPPTTIIOONN + 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. + + 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. + + The command name (argv[0]) is set to the name of the des- + tination printer. + +EENNVVIIRROONNMMEENNTT VVAARRIIAABBLLEESS + The following environment variables are defined by the + CUPS server when executing each filter: + + CHARSET + The default text character set (typically us-ascii or + iso-8859-1). + + CONTENT_TYPE + The MIME type associated with the file (e.g. applica- + tion/postscript). + + DEVICE_URI + The device-uri associated with the printer. + + LANG + The default language locale (typically C or en). + + PATH + The standard execution path for external programs + that may be run by the filter. + + PPD + The full pathname of the PostScript Printer Descrip- + tion (PPD) file for this printer. + + PRINTER + The name of the printer; this is provided for shell + scripts which may not be able to get the passed + argv[0] string. + + RIP_CACHE + The recommended amount of memory to use for Raster + Image Processors (RIPs). + + + +22 September 1999 Common UNIX Printing System 1 + + + + + +filter(1) Easy Software Products filter(1) + + + SERVER_ROOT + The root directory of the server. + + SOFTWARE + The name and version number of the server (typically + CUPS/1.0). + + TZ + The timezone of the server. + + USER + The user executing the filter (typically lp). + +CCOOMMPPAATTIIBBIILLIITTYY + 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 inter- + face script will be provided via the llppaaddmmiinn((88)) command + using the _-_i option. + +SSEEEE AALLSSOO + backend(1), cupsd(8), CUPS Software Administrators Manual, + CUPS Interface Design Description + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 2 + + diff --git a/man/filter.man b/man/filter.man new file mode 100644 index 0000000000..b32c8c688e --- /dev/null +++ b/man/filter.man @@ -0,0 +1,108 @@ +.\" +.\" "$Id: filter.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" filter man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 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 +CONTENT_TYPE +.br +The MIME type associated with the file (e.g. application/postscript). +.TP 5 +DEVICE_URI +.br +The device-uri associated with the printer. +.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 +PRINTER +.br +The name of the printer; this is provided for shell scripts which may not be +able to get the passed argv[0] string. +.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. +.TP 5 +USER +.br +The user executing the filter (typically lp). +.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 Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: filter.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/lp.1 b/man/lp.1 new file mode 100644 index 0000000000..e01fca04ff --- /dev/null +++ b/man/lp.1 @@ -0,0 +1,132 @@ + + + +lp(1) Easy Software Products lp(1) + + +NNAAMMEE + lp - print files + cancel - cancel jobs + +SSYYNNOOPPSSIISS + llpp [ -c ] [ -d _d_e_s_t_i_n_a_t_i_o_n ] [ -h _s_e_r_v_e_r ] [ -m ] [ -n + _n_u_m_-_c_o_p_i_e_s [ -o _o_p_t_i_o_n ] [ -p/q _p_r_i_o_r_i_t_y ] [ -s ] [ -t + _t_i_t_l_e ] [ _f_i_l_e_(_s_) ] + ccaanncceell [ -a ] [ -h _s_e_r_v_e_r ] [ _i_d ] [ _d_e_s_t_i_n_a_t_i_o_n ] [ _d_e_s_- + _t_i_n_a_t_i_o_n_-_i_d ] + +DDEESSCCRRIIPPTTIIOONN + llpp submits files for printing. + + ccaanncceell cancels existing print jobs. The _-_a option will + remove all jobs from the specified destination. + +OOPPTTIIOONNSS + The following options are recognized by llpp: + + -d _d_e_s_t_i_n_a_t_i_o_n + Prints files to the named printer. + + -h _h_o_s_t_n_a_m_e + Specifies the print server hostname. The default is + "localhost" or the value of the CUPS_SERVER environ- + ment variable. + + -m + Send email when the job is completed (ignored in CUPS + 1.0.) + + -n _c_o_p_i_e_s + Sets the number of copies to print from 1 to 100. + + -o _o_p_t_i_o_n + Sets a job option. + + -p/q _p_r_i_o_r_i_t_y + Sets the job priority from 1 (lowest) to 100 (high- + est). The default priority is 50. + + -s + Do not report the resulting job IDs (silent mode.) + + -t _n_a_m_e + Sets the job name. + +CCOOMMPPAATTIIBBIILLIITTYY + 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 nnoott case-sensitive. + + The "m" option is not functional in CUPS 1.0. + + + +9 September 1999 Common UNIX Printing System 1 + + + + + +lp(1) Easy Software Products lp(1) + + +SSEEEE AALLSSOO + lpstat(1), CUPS Software Users Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +9 September 1999 Common UNIX Printing System 2 + + diff --git a/man/lp.man b/man/lp.man new file mode 100644 index 0000000000..cc5a5f8eff --- /dev/null +++ b/man/lp.man @@ -0,0 +1,111 @@ +.\" +.\" "$Id: lp.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" lp/cancel man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "9 September 1999" "Easy Software Products" +.SH NAME +lp \- print files +.br +cancel \- cancel jobs +.SH SYNOPSIS +.B lp +[ \-c ] [ \-d +.I destination +] [ -h +.I server +] [ \-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 OPTIONS +The following options are recognized by \fBlp\fR: +.TP 5 +\-d \fIdestination\fR +.br +Prints files to the named printer. +.TP 5 +\-h \fIhostname\fR +.br +Specifies the print server hostname. The default is "localhost" or the value +of the CUPS_SERVER environment variable. +.TP 5 +\-m +.br +Send email when the job is completed (ignored in CUPS 1.0.) +.TP 5 +\-n \fIcopies\fR +.br +Sets the number of copies to print from 1 to 100. +.TP 5 +\-o \fIoption\fR +.br +Sets a job option. +.TP 5 +\-p/q \fIpriority\fR +.br +Sets the job priority from 1 (lowest) to 100 (highest). The default priority +is 50. +.TP 5 +\-s +.br +Do not report the resulting job IDs (silent mode.) +.TP 5 +\-t \fIname\fR +.br +Sets the job name. +.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 "m" option is not functional in CUPS 1.0. +.SH SEE ALSO +lpstat(1), +CUPS Software Users Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lp.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/lpadmin.8 b/man/lpadmin.8 new file mode 100644 index 0000000000..6504b1c483 --- /dev/null +++ b/man/lpadmin.8 @@ -0,0 +1,132 @@ + + + +lpadmin(8) Easy Software Products lpadmin(8) + + +NNAAMMEE + lpadmin - configure cups printers and classes + +SSYYNNOOPPSSIISS + llppaaddmmiinn [ -h _s_e_r_v_e_r ] -d _d_e_s_t_i_n_a_t_i_o_n + llppaaddmmiinn [ -h _s_e_r_v_e_r ] -p _p_r_i_n_t_e_r _o_p_t_i_o_n_(_s_) + llppaaddmmiinn [ -h _s_e_r_v_e_r ] -x _d_e_s_t_i_n_a_t_i_o_n + +DDEESSCCRRIIPPTTIIOONN + _l_p_a_d_m_i_n configures printer and class queues provided by + CUPS. It can also be used to set the system default + printer or class. + + The first form of the command sets the default printer or + class to _d_e_s_t_i_n_a_t_i_o_n. Subsequent print jobs submitted via + the _l_p_(_1_) or _l_p_r_(_1_) commands will use this destination + unless the user specifies otherwise. + + The second form of the command configures the named + printer. The additional options are described below. + + The third form of the command deletes the printer or class + _d_e_s_t_i_n_a_t_i_o_n. Any jobs that are pending for the destina- + tion will be removed and any job that is currently printed + will be aborted. + +CCOONNFFIIGGUURRAATTIIOONN OOPPTTIIOONNSS + The following options are recognized when configuring a + printer queue: + + -c _c_l_a_s_s + Adds the named _p_r_i_n_t_e_r to _c_l_a_s_s. If _c_l_a_s_s does not + exist it is created automatically. + + -i _i_n_t_e_r_f_a_c_e + Sets a System V style interface script for the + printer. This option cannot be specified with the _-_P + option (PPD file) and is intended for providing sup- + port for legacy printer drivers. + + -m _m_o_d_e_l + Sets a standard System V interface script or PPD file + from the model directory. + + -r _c_l_a_s_s + Removes the named _p_r_i_n_t_e_r from _c_l_a_s_s. If the result- + ing class becomes empty it is removed. + + -v _d_e_v_i_c_e_-_u_r_i + Sets the _d_e_v_i_c_e_-_u_r_i attribute of the printer queue. + If _d_e_v_i_c_e_-_u_r_i is a filename it is automatically con- + verted to the form ffiillee:://ffiillee//nnaammee. + + + + + +22 September 1999 Common UNIX Printing System 1 + + + + + +lpadmin(8) Easy Software Products lpadmin(8) + + + -D _i_n_f_o + Provides a textual description of the printer. + + -E + Enables the printer and accepts jobs; this is the + same as running the _a_c_c_e_p_t_(_8_) and _e_n_a_b_l_e_(_8_) programs + on the printer. + + -L _l_o_c_a_t_i_o_n + Provides a textual location of the printer. + + -P _p_p_d_-_f_i_l_e + Specifies a PostScript Printer Description file to + use with the printer. If specified, this option over- + rides the _-_i option (interface script). + +CCOOMMPPAATTIIBBIILLIITTYY + 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 nnoott case-sensitive. + Finally, the CUPS version of _l_p_a_d_m_i_n may ask the user for + an access password depending on the printing system con- + figuration. This differs from the System V version which + requires the root user to execute this command. + +LLIIMMIITTAATTIIOONNSS + The CUPS version of _l_p_a_d_m_i_n does not support all of the + System V or Solaris printing system configuration options. + +SSEEEE AALLSSOO + accept(8), cancel(1), disable(8), enable(8), lp(1), + lpstat(1), reject(8), CUPS Software Administrators Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 2 + + diff --git a/man/lpadmin.man b/man/lpadmin.man new file mode 100644 index 0000000000..1b3e1f81cd --- /dev/null +++ b/man/lpadmin.man @@ -0,0 +1,124 @@ +.\" +.\" "$Id: lpadmin.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" lpadmin man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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 September 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 +\fIlpadmin\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 and accepts jobs; 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 \fIlpadmin\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 \fIlpadmin\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 Administrators Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpadmin.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/lpc.8 b/man/lpc.8 new file mode 100644 index 0000000000..0f77d52d8d --- /dev/null +++ b/man/lpc.8 @@ -0,0 +1,66 @@ + + + +lpc(8) Easy Software Products lpc(8) + + +NNAAMMEE + lpc - line printer control program + +SSYYNNOOPPSSIISS + llppcc [ _c_o_m_m_a_n_d [ _p_a_r_a_m_e_t_e_r_(_s_) ] ] + +DDEESSCCRRIIPPTTIIOONN + _l_p_c provides limited control over printer and class queues + provided by CUPS. It can also be used to query the state + of queues. + + If no command is specified on the command-line, lpc will + display a prompt and accept commands from the standard + input. + +CCOOMMMMAANNDDSS + The _l_p_c program accepts a subset of commands accepted by + the Berkeley _l_p_c program of the same name: + + _e_x_i_t + Exits the command interpreter. + + help _[_c_o_m_m_a_n_d_] + Displays a short help message. + + quit + Exits the command interpreter. + + status _[_q_u_e_u_e_] + Displays the status of one or more printer or class + queues. + + ? _[_c_o_m_m_a_n_d_] + Display a short help message. + +LLIIMMIITTAATTIIOONNSS + Since _l_p_c is geared towards the Berkeley printing system, + it is impossible to use _l_p_c to configure printer or class + queues provided by CUPS. To configure printer or class + queues you must use the _l_p_a_d_m_i_n_(_8_) command or another + CUPS-compatible client with that functionality. + +CCOOMMPPAATTIIBBIILLIITTYY + The CUPS version of _l_p_c does not implement all of the + standard Berkeley commands. + +SSEEEE AALLSSOO + accept(8), cancel(1), disable(8), enable(8), lp(1), + lpr(1), lprm(1), lpstat(1), reject(8), CUPS Software + Administrators Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/lpc.man b/man/lpc.man new file mode 100644 index 0000000000..6e357b7924 --- /dev/null +++ b/man/lpc.man @@ -0,0 +1,79 @@ +.\" +.\" "$Id: lpc.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" lpc man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +lpc \- line printer control program +.SH SYNOPSIS +.B lpc +[ +.I command +[ +.I parameter(s) +] ] +.SH DESCRIPTION +\fIlpc\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 \fIlpc\fR program accepts a subset of commands accepted by the Berkeley +\fIlpc\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 \fIlpc\fR is geared towards the Berkeley printing system, it is impossible +to use \fIlpc\fR to configure printer or class queues provided by CUPS. To +configure printer or class queues you must use the \fIlpadmin(8)\fR command +or another CUPS-compatible client with that functionality. +.SH COMPATIBILITY +The CUPS version of \fIlpc\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 Administrators Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpc.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/lpq.1 b/man/lpq.1 new file mode 100644 index 0000000000..b153b687e4 --- /dev/null +++ b/man/lpq.1 @@ -0,0 +1,66 @@ + + + +lpq(1) Easy Software Products lpq(1) + + +NNAAMMEE + lpq - show printer queue status + +SSYYNNOOPPSSIISS + llppqq [ -P _d_e_s_t ] [ -l ] [ _+_i_n_t_e_r_v_a_l ] + +DDEESSCCRRIIPPTTIIOONN + _l_p_q shows the current print queue status on the named + printer. Jobs queued on the default destination will be + shown if no printer or class is specified on the command- + line. + + The _i_n_t_e_r_v_a_l option allows you to continuously report the + jobs in the queue until the queue is empty; the list of + jobs is show one every _i_n_t_e_r_v_a_l seconds. + + The _-_l option requests a more verbose reporting format. + +SSEEEE AALLSSOO + cancel(1), lp(1), lpr(1), lprm(1), lpstat(1) + CUPS Software Users Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +7 December 1999 Common UNIX Printing System 1 + + diff --git a/man/lpq.man b/man/lpq.man new file mode 100644 index 0000000000..2879a0fcb2 --- /dev/null +++ b/man/lpq.man @@ -0,0 +1,52 @@ +.\" +.\" "$Id: lpq.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" lpq man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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 lpq 1 "Common UNIX Printing System" "7 December 1999" "Easy Software Products" +.SH NAME +lpq \- show printer queue status +.SH SYNOPSIS +.B lpq +[ \-P +.I dest +] [ \-l ] [ +.I +interval +] +.SH DESCRIPTION +\fIlpq\fR shows the current print queue status on the named printer. +Jobs queued on the default destination will be shown if no printer or +class is specified on the command-line. +.LP +The \fIinterval\fR option allows you to continuously report the jobs +in the queue until the queue is empty; the list of jobs is show one +every \fIinterval\fR seconds. +.LP +The \fI-l\fR option requests a more verbose reporting format. +.SH SEE ALSO +cancel(1), lp(1), lpr(1), lprm(1), lpstat(1) +.br +CUPS Software Users Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpq.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/lpr.1 b/man/lpr.1 new file mode 100644 index 0000000000..7597c5e7b5 --- /dev/null +++ b/man/lpr.1 @@ -0,0 +1,132 @@ + + + +lpr(1) Easy Software Products lpr(1) + + +NNAAMMEE + lpr - print files + +SSYYNNOOPPSSIISS + llpprr [ -P _d_e_s_t_i_n_a_t_i_o_n ] [ -# _n_u_m_-_c_o_p_i_e_s [ -l ] [ -o _o_p_t_i_o_n + ] [ -p] [ -r ] [ -C/J/T _t_i_t_l_e ] [ _f_i_l_e_(_s_) ] + +DDEESSCCRRIIPPTTIIOONN + llpprr 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 llpprr reads the print file + from the standard input. + +OOPPTTIIOONNSS + The following options are recognized by llpprr: + + -P _d_e_s_t_i_n_a_t_i_o_n + Prints files to the named printer. + + -# _c_o_p_i_e_s + Sets the number of copies to print from 1 to 100. + + -C _n_a_m_e + Sets the job name. + + -J _n_a_m_e + Sets the job name. + + -T _n_a_m_e + Sets the job name. + + -l + Specifies that the print file is already formatted + for the destination and should be sent without fil- + tering. This option is equivalent to "-oraw". + + -o _o_p_t_i_o_n + Sets a job option. + + -p + 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. + + -r + Specifies that the named print files should be + deleted after printing them. + +CCOOMMPPAATTIIBBIILLIITTYY + The "c", "d", "f", "g", "i", "m", "n", "t", "v", and "w" + options are not supported by CUPS and will produce a + + + +9 September 1999 Common UNIX Printing System 1 + + + + + +lpr(1) Easy Software Products lpr(1) + + + warning message if used. + +SSEEEE AALLSSOO + cancel(1), lp(1), lpstat(1), CUPS Software Users Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +9 September 1999 Common UNIX Printing System 2 + + diff --git a/man/lpr.man b/man/lpr.man new file mode 100644 index 0000000000..ec91d456e0 --- /dev/null +++ b/man/lpr.man @@ -0,0 +1,96 @@ +.\" +.\" "$Id: lpr.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" lpr man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "9 September 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 a job option. +.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 Users Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpr.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/lprm.1 b/man/lprm.1 new file mode 100644 index 0000000000..475461b584 --- /dev/null +++ b/man/lprm.1 @@ -0,0 +1,66 @@ + + + +lprm(1) Easy Software Products lprm(1) + + +NNAAMMEE + lprm - cancel print jobs + +SSYYNNOOPPSSIISS + llpprrmm [ - ] [ -P _d_e_s_t_i_n_a_t_i_o_n ] [ _j_o_b _I_D_(_s_) ] + +DDEESSCCRRIIPPTTIIOONN + llpprrmm cancels print jobs that have been queued for print- + ing. The _-_P option specifies the destination printer or + class. + + If no arguments are supplied, the current job on the + default destination is cancelled. You can specify one or + more job ID numbers to cancel those jobs, or use the _- + option to cancel all jobs. + +CCOOMMPPAATTIIBBIILLIITTYY + The CUPS version of _l_p_r_m is compatible with the standard + Berkeley _l_p_r_m command. + +SSEEEE AALLSSOO + cancel(1), lp(1), lpstat(1), lpr(1), CUPS Software Users + Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/lprm.man b/man/lprm.man new file mode 100644 index 0000000000..5c3a58aa83 --- /dev/null +++ b/man/lprm.man @@ -0,0 +1,51 @@ +.\" +.\" "$Id: lprm.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" lprm man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +lprm \- cancel print jobs +.SH SYNOPSIS +.B lprm +[ - ] [ -P +.I destination +] [ +.I job ID(s) +] +.SH DESCRIPTION +\fBlprm\fR cancels print jobs that have been queued for printing. The \fI-P\fR +option specifies the destination printer or class. +.LP +If no arguments are supplied, the current job on the default destination is +cancelled. You can specify one or more job ID numbers to cancel those jobs, +or use the \fI\-\fR option to cancel all jobs. +.SH COMPATIBILITY +The CUPS version of \fIlprm\fR is compatible with the standard Berkeley +\fIlprm\fR command. +.SH SEE ALSO +cancel(1), lp(1), lpstat(1), lpr(1), +CUPS Software Users Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lprm.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/lpstat.1 b/man/lpstat.1 new file mode 100644 index 0000000000..ac5c8f42c7 --- /dev/null +++ b/man/lpstat.1 @@ -0,0 +1,132 @@ + + + +lpstat(1) Easy Software Products lpstat(1) + + +NNAAMMEE + lpstat - print cups status information + +SSYYNNOOPPSSIISS + llppssttaatt [ -a [ _d_e_s_t_i_n_a_t_i_o_n_(_s_) ] ] [ -c [ _c_l_a_s_s_(_e_s_) ] ] [ -d + ] [ -h _s_e_r_v_e_r ] [ -o [ _d_e_s_t_i_n_a_t_i_o_n_(_s_) ] ] [ -p [ + _p_r_i_n_t_e_r_(_s_) ] ] [ -r ] [ -s ] [ -t ] [ -u [ _u_s_e_r_(_s_) ] ] [ + -v [ _p_r_i_n_t_e_r_(_s_) ] ] + +DDEESSCCRRIIPPTTIIOONN + llppssttaatt displays status information about the current + classes, jobs, and printers. When run with no arguments, + llppssttaatt will list jobs queued by the user. Other options + include: + + -a [_p_r_i_n_t_e_r_(_s_)] + Shows the accepting state of printer queues. If no + printers are specified then all printers are listed. + + -c [_c_l_a_s_s_(_e_s_)] + Shows the printer classes and the printers that + belong to them. If no classes are specified then all + classes are listed. + + -d + Shows the current default destination. + + -h _s_e_r_v_e_r + Specifies the CUPS server to communicate with. + + -o [_d_e_s_t_i_n_a_t_i_o_n_(_s_)] + Shows the jobs queue on the specified destinations. + If no destinations are specified all jobs are shown. + + -p [_p_r_i_n_t_e_r_(_s_)] + Shows the printers and whether or not they are + enabled for printing. If no printers are specified + then all printers are listed. + + -r + Shows whether or not the CUPS server is running. + + -s + 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. + + -t + Shows all status information. This is equivalent to + using the "-r", "-d", "-c", "-d", "-v", "-a", "-p", + and "-o" options. + + + + +22 September 1999 Common UNIX Printing System 1 + + + + + +lpstat(1) Easy Software Products lpstat(1) + + + -u [_u_s_e_r_(_s_)] + Shows a list of print jobs queued by the specified + users. If no users are specified, lists the jobs + queued by the current user. + + -v [_p_r_i_n_t_e_r_(_s_)] + Shows the printers and what device they are attached + to. If no printers are specified then all printers + are listed. + +CCOOMMPPAATTIIBBIILLIITTYY + 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 nnoott case-sensitive. + + The "-h" option is not a standard System V option. + +SSEEEE AALLSSOO + cancel(1), lp(1), CUPS Software Users Manual + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 2 + + diff --git a/man/lpstat.man b/man/lpstat.man new file mode 100644 index 0000000000..a6af5296ae --- /dev/null +++ b/man/lpstat.man @@ -0,0 +1,115 @@ +.\" +.\" "$Id: lpstat.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" lpstat man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 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 Users Manual +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpstat.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/mime.convs.5 b/man/mime.convs.5 new file mode 100644 index 0000000000..5e70155ffc --- /dev/null +++ b/man/mime.convs.5 @@ -0,0 +1,66 @@ + + + +mime.convs(5) Easy Software Products mime.convs(5) + + +NNAAMMEE + mime.convs - mime type conversion file for cups + +DDEESSCCRRIIPPTTIIOONN + The _m_i_m_e_._c_o_n_v_s file defines the filters that are available + for converting files from one format to another. The stan- + dard filters support text, PDF, PostScript, HP-GL/2, and + many types of image files. + + Additional filters can be added to the _m_i_m_e_._c_o_n_v_s file or + to other files in the configuration directory + (//vvaarr//ccuuppss//ccoonnff) with the extension ".convs". + +SSEEEE AALLSSOO + classes.conf(5), cupsd(8), cupsd.conf(5), mime.types(5), + printers.conf(5), CUPS Software Administrators Manual, + CUPS Interface Design Description + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/mime.convs.man b/man/mime.convs.man new file mode 100644 index 0000000000..e764f9e6f8 --- /dev/null +++ b/man/mime.convs.man @@ -0,0 +1,43 @@ +.\" +.\" "$Id: mime.convs.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" mime.convs man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +mime.convs \- mime type conversion file for cups +.SH DESCRIPTION +The \fImime.convs\fR file defines the filters that are available for +converting files from one format to another. The standard filters +support text, PDF, PostScript, HP-GL/2, and many types of image files. +.LP +Additional filters can be added to the \fImime.convs\fR file or to +other files in the configuration directory (\fB/var/cups/conf\fR) with +the extension ".convs". +.SH SEE ALSO +classes.conf(5), cupsd(8), cupsd.conf(5), mime.types(5), printers.conf(5), +CUPS Software Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: mime.convs.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/mime.types.5 b/man/mime.types.5 new file mode 100644 index 0000000000..8fdc6b9660 --- /dev/null +++ b/man/mime.types.5 @@ -0,0 +1,66 @@ + + + +mime.types(5) Easy Software Products mime.types(5) + + +NNAAMMEE + mime.types - mime type description file for cups + +DDEESSCCRRIIPPTTIIOONN + The _m_i_m_e_._t_y_p_e_s file defines the recognized file types. + + Additional file types can be added to _m_i_m_e_._t_y_p_e_s or in + additional files in the configuration directory + //vvaarr//ccuuppss//ccoonnff with the extension ".types". + +SSEEEE AALLSSOO + classes.conf(5), cupsd(8), cupsd.conf(5), mime.convs(5), + printers.conf(5), CUPS Software Administrators Manual, + CUPS Interface Design Description + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/mime.types.man b/man/mime.types.man new file mode 100644 index 0000000000..049302455a --- /dev/null +++ b/man/mime.types.man @@ -0,0 +1,40 @@ +.\" +.\" "$Id: mime.types.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" mime.types man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +mime.types \- mime type description file for cups +.SH DESCRIPTION +The \fImime.types\fR file defines the recognized file types. +.LP +Additional file types can be added to \fImime.types\fR or in additional files +in the configuration directory \fB/var/cups/conf\fR with the extension ".types". +.SH SEE ALSO +classes.conf(5), cupsd(8), cupsd.conf(5), mime.convs(5), printers.conf(5), +CUPS Software Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: mime.types.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/man/printers.conf.5 b/man/printers.conf.5 new file mode 100644 index 0000000000..46456d1ea1 --- /dev/null +++ b/man/printers.conf.5 @@ -0,0 +1,66 @@ + + + +printers.conf(5) Easy Software Products printers.conf(5) + + +NNAAMMEE + printers.conf - printer configuration file for cups + +DDEESSCCRRIIPPTTIIOONN + The _p_r_i_n_t_e_r_s_._c_o_n_f file defines the local printers that are + available. It is normally generated by the _c_u_p_s_d_(_8_) pro- + gram when printers are added, deleted, or modified. + +SSEEEE AALLSSOO + classes.conf(5), cupsd(8), cupsd.conf(5), mime.convs(5), + mime.types(5), CUPS Software Administrators Manual, CUPS + Interface Design Description + +CCOOPPYYRRIIGGHHTT + Copyright 1993-2000 by Easy Software Products, All Rights + Reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +22 September 1999 Common UNIX Printing System 1 + + diff --git a/man/printers.conf.man b/man/printers.conf.man new file mode 100644 index 0000000000..eae17b7041 --- /dev/null +++ b/man/printers.conf.man @@ -0,0 +1,39 @@ +.\" +.\" "$Id: printers.conf.man 911 2000-02-23 03:17:06Z mike $" +.\" +.\" printers.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2000 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" "22 September 1999" "Easy Software Products" +.SH NAME +printers.conf \- printer configuration file for cups +.SH DESCRIPTION +The \fIprinters.conf\fR file defines the local printers that are +available. It is normally generated by the \fIcupsd(8)\fR program when +printers are added, deleted, or modified. +.SH SEE ALSO +classes.conf(5), cupsd(8), cupsd.conf(5), mime.convs(5), mime.types(5), +CUPS Software Administrators Manual, +CUPS Interface Design Description +.SH COPYRIGHT +Copyright 1993-2000 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: printers.conf.man 911 2000-02-23 03:17:06Z mike $". +.\" diff --git a/ppd/Makefile b/ppd/Makefile new file mode 100644 index 0000000000..511b476f65 --- /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 stcolor.ppd stphoto.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..c21a28887c --- /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-2000 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 +*% +*FormatVersion: "4.3" +*FileVersion: "1.1" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "DESKJET.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.1)" +*cupsVersion: 1.1 +*cupsManualCopies: True +*cupsFilter: "application/vnd.cups-raster 0 rastertohp" +*ModelName: "HP DeskJet Series" +*ShortNickName: "HP DeskJet Series" +*NickName: "HP DeskJet Series CUPS v1.1" +*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..ca9e3a6317 --- /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-2000 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 +*% +*FormatVersion: "4.3" +*FileVersion: "1.1" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "LASERJET.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.1)" +*cupsVersion: 1.1 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-raster 0 rastertohp" +*ModelName: "HP LaserJet Series" +*ShortNickName: "HP LaserJet Series" +*NickName: "HP LaserJet Series CUPS v1.1" +*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/ppd/stcolor.ppd b/ppd/stcolor.ppd new file mode 100644 index 0000000000..7ecbef95d9 --- /dev/null +++ b/ppd/stcolor.ppd @@ -0,0 +1,131 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id$" +*% +*% Sample EPSON Stylus Color driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2000 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 +*% +*FormatVersion: "4.3" +*FileVersion: "1.1" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "STCOLOR.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.1)" +*cupsVersion: 1.1 +*cupsManualCopies: True +*cupsFilter: "application/vnd.cups-raster 0 rastertoepson" +*cupsColorProfile 180dpi/-: "1.0 1.0 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0" +*cupsColorProfile 360dpi/-: "1.0 1.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0" +*cupsColorProfile 720dpi/-: "1.0 2.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0" +*ModelName: "EPSON Stylus Color Series" +*ShortNickName: "EPSON Stylus Color Series" +*NickName: "EPSON Stylus Color Series CUPS v1.1" +*PSVersion: "(2017.000) 0" +*LanguageLevel: "2" +*ColorDevice: True +*DefaultColorSpace: RGB +*FileSystem: False +*Throughput: "1" +*LandscapeOrientation: Plus90 +*VariablePaperSize: False +*TTRasterizer: Type42 + +*OpenUI *PageSize/Media Size: PickOne +*OrderDependency: 10 AnySetup *PageSize +*DefaultPageSize: Letter +*PageSize Letter: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter: "8.60 39.60 603.40 766.49" +*ImageableArea Legal: "8.60 39.60 603.40 982.49" +*ImageableArea A4: "8.60 39.60 586.40 816.49" + +*DefaultPaperDimension: Letter +*PaperDimension Letter: "612 792" +*PaperDimension Legal: "612 1008" +*PaperDimension A4: "595 842" + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 360dpi +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice{0.6666 exp}bind settransfer" +*Resolution 720dpi/720 DPI: "<>setpagedevice{0.4 exp}bind settransfer" +*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/stphoto.ppd b/ppd/stphoto.ppd new file mode 100644 index 0000000000..08bf671efc --- /dev/null +++ b/ppd/stphoto.ppd @@ -0,0 +1,131 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id$" +*% +*% Sample EPSON Stylus Photo driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2000 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 +*% +*FormatVersion: "4.3" +*FileVersion: "1.1" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "STPHOTO.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.1)" +*cupsVersion: 1.1 +*cupsManualCopies: True +*cupsFilter: "application/vnd.cups-raster 0 rastertoepson" +*cupsColorProfile 180dpi/-: "1.0 1.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0" +*cupsColorProfile 360dpi/-: "1.0 1.5 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0" +*cupsColorProfile 720dpi/-: "1.0 2.5 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0" +*ModelName: "EPSON Stylus Photo Series" +*ShortNickName: "EPSON Stylus Photo Series" +*NickName: "EPSON Stylus Photo Series CUPS v1.1" +*PSVersion: "(2017.000) 0" +*LanguageLevel: "2" +*ColorDevice: True +*DefaultColorSpace: RGB +*FileSystem: False +*Throughput: "1" +*LandscapeOrientation: Plus90 +*VariablePaperSize: False +*TTRasterizer: Type42 + +*OpenUI *PageSize/Media Size: PickOne +*OrderDependency: 10 AnySetup *PageSize +*DefaultPageSize: Letter +*PageSize Letter: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter: "8.60 39.60 603.40 766.49" +*ImageableArea Legal: "8.60 39.60 603.40 982.49" +*ImageableArea A4: "8.60 39.60 586.40 816.49" + +*DefaultPaperDimension: Letter +*PaperDimension Letter: "612 792" +*PaperDimension Legal: "612 1008" +*PaperDimension A4: "595 842" + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 360dpi +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice{0.6666 exp}bind settransfer" +*Resolution 720dpi/720 DPI: "<>setpagedevice{0.4 exp}bind settransfer" +*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/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..c94b6b9ac6 --- /dev/null +++ b/pstoraster/Makefile @@ -0,0 +1,435 @@ +# +# "$Id$" +# +# GNU Ghostscript makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2000 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 = gconfig.o \ + gdevabuf.o \ + gdevbbox.o \ + gdevcups.o \ + gdevdbit.o \ + gdevddrw.o \ + gdevdflt.o \ + gdevdgbr.o \ + gdevhit.o \ + gdevm16.o \ + gdevm1.o \ + gdevm24.o \ + gdevm2.o \ + gdevm32.o \ + gdevm4.o \ + gdevm8.o \ + gdevmem.o \ + gdevmpla.o \ + gdevnfwd.o \ + gdevpipe.o \ + gdevprn.o \ + gdevpsde.o \ + gdevpsdf.o \ + gdevpsdi.o \ + gdevpsdp.o \ + gdevpsds.o \ + gdevpstr.o \ + gdevps.o \ + gdevvec.o \ + gp_getnv.o \ + gp_nofb.o \ + gp_nsync.o \ + gp_unifn.o \ + gp_unifs.o \ + gp_unix.o \ + gsalloc.o \ + gsalpha.o \ + gsargs.o \ + gsbitops.o \ + gsbittab.o \ + gscdefs.o \ + gscdevn.o \ + gschar0.o \ + gschar.o \ + gscie.o \ + gsclipsr.o \ + gscolor1.o \ + gscolor2.o \ + gscolor3.o \ + gscolor.o \ + gscoord.o \ + gscparam.o \ + gscpixel.o \ + gscrdp.o \ + gscrd.o \ + gscscie.o \ + gscsepr.o \ + gscspace.o \ + gsdevice.o \ + gsdevmem.o \ + gsdparam.o \ + gsdps1.o \ + gsdsrc.o \ + gsfcmap.o \ + gsfont0.o \ + gsfont.o \ + gsfunc0.o \ + gsfunc3.o \ + gsfunc.o \ + gshsb.o \ + gsht1.o \ + gshtscr.o \ + gsht.o \ + gsimage.o \ + gsimpath.o \ + gsinit.o \ + gsiodev.o \ + gsline.o \ + gsmalloc.o \ + gsmatrix.o \ + gsmemory.o \ + gsmisc.o \ + gsnorop.o \ + gspaint.o \ + gsparams.o \ + gsparam.o \ + gspath1.o \ + gspath.o \ + gspcolor.o \ + gsshade.o \ + gsstate.o \ + gstext.o \ + gstrap.o \ + gstype1.o \ + gstype2.o \ + gstype42.o \ + gsutil.o \ + gxacpath.o \ + gxbcache.o \ + gxccache.o \ + gxccman.o \ + gxcht.o \ + gxclbits.o \ + gxclimag.o \ + gxclip2.o \ + gxclipm.o \ + gxclip.o \ + gxclist.o \ + gxclmem.o \ + gxclpage.o \ + gxclpath.o \ + gxclrast.o \ + gxclread.o \ + gxclrect.o \ + gxclutil.o \ + gxclzlib.o \ + gxcmap.o \ + gxcpath.o \ + gxctable.o \ + gxdcconv.o \ + gxdcolor.o \ + gxdither.o \ + gxfill.o \ + gxhint1.o \ + gxhint2.o \ + gxhint3.o \ + gxht.o \ + gxi12bit.o \ + gxicolor.o \ + gxidata.o \ + gxifast.o \ + gxiinit.o \ + gximage3.o \ + gximage4.o \ + gximono.o \ + gxiscale.o \ + gxmclip.o \ + gxp1fill.o \ + gxpaint.o \ + gxpath2.o \ + gxpath.o \ + gxpcmap.o \ + gxpcopy.o \ + gxpdash.o \ + gxpflat.o \ + gxsample.o \ + gxshade1.o \ + gxshade4.o \ + gxshade6.o \ + gxshade.o \ + gxstroke.o \ + gxtype1.o \ + ialloc.o \ + ibnum.o \ + iccinit0.o \ + iconfig.o \ + icontext.o \ + idebug.o \ + idict.o \ + idparam.o \ + idstack.o \ + igcref.o \ + igcstr.o \ + igc.o \ + iinit.o \ + ilocate.o \ + imainarg.o \ + imain.o \ + iname.o \ + interp.o \ + iparam.o \ + ireclaim.o \ + isave.o \ + iscanbin.o \ + iscannum.o \ + iscan.o \ + istack.o \ + iutil2.o \ + iutil.o \ + sbcp.o \ + sbhc.o \ + sbwbs.o \ + scantab.o \ + scfdtab.o \ + scfd.o \ + scfetab.o \ + scfe.o \ + scfparam.o \ + sdcparam.o \ + sdctc.o \ + sdctd.o \ + sdcte.o \ + sddparam.o \ + sdeparam.o \ + seexec.o \ + sfilter1.o \ + sfilter2.o \ + sfxstdio.o \ + shcgen.o \ + shc.o \ + siscale.o \ + sjpegc.o \ + sjpegd.o \ + sjpegerr.o \ + sjpege.o \ + slzwce.o \ + slzwc.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 \ + zcfont.o \ + zchar1.o \ + zchar2.o \ + zchar32.o \ + zchar42.o \ + zcharout.o \ + zchar.o \ + zcid.o \ + zcie.o \ + zcolor1.o \ + zcolor2.o \ + zcolor.o \ + zcontrol.o \ + zcrd.o \ + zcsdevn.o \ + zcsindex.o \ + zcspixel.o \ + zcssepr.o \ + zdevcal.o \ + zdevice2.o \ + zdevice.o \ + zdict.o \ + zdps1.o \ + zfbcp.o \ + zfcmap.o \ + zfdctd.o \ + zfdcte.o \ + zfdecode.o \ + zfileio.o \ + zfile.o \ + zfilter2.o \ + zfilterx.o \ + zfilter.o \ + zfname.o \ + zfont0.o \ + zfont1.o \ + zfont2.o \ + zfont32.o \ + zfont42.o \ + zfont.o \ + zfproc.o \ + zfreuse.o \ + zfunc0.o \ + zfunc3.o \ + zfunc.o \ + zfzlib.o \ + zgeneric.o \ + zgstate.o \ + zhsb.o \ + zht1.o \ + zht2.o \ + zht.o \ + zimage2.o \ + zimage3.o \ + zimage.o \ + ziodev2.o \ + ziodev.o \ + zmath.o \ + zmatrix.o \ + zmedia2.o \ + zmisc1.o \ + zmisc2.o \ + zmisc3.o \ + zmisc.o \ + zpacked.o \ + zpaint.o \ + zpath1.o \ + zpath.o \ + zpcolor.o \ + zrelbit.o \ + zshade.o \ + zstack.o \ + zstring.o \ + zsysvm.o \ + ztoken.o \ + ztrap.o \ + ztype.o \ + zupath.o \ + zusparam.o \ + zvmem2.o \ + zvmem.o \ + +OBJS = $(LIBOBJS) genarch.o pstoraster.o + +# +# Data files... +# + +DFILES = Fontmap \ + gs_btokn.ps gs_ccfnt.ps gs_cff.ps gs_cidfn.ps \ + gs_cmap.ps gs_cmdl.ps gs_dbt_e.ps gs_diskf.ps \ + gs_dpnxt.ps gs_dps1.ps gs_dps2.ps gs_dps.ps gs_epsf.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_ll3.ps gs_mex_e.ps gs_mro_e.ps gs_pdfwr.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_typ32.ps gs_typ42.ps gs_type1.ps gs_wan_e.ps \ + gs_wl1_e.ps gs_wl2_e.ps gs_wl5_e.ps pdf2dsc.ps \ + pdf_base.ps pdf_draw.ps pdf_font.ps pdf_main.ps \ + pdf_ops.ps pdf_sec.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) $(SERVERBIN)/filter + $(CP) pstoraster $(SERVERBIN)/filter + $(RM) $(SERVERBIN)/filter/pdftops + $(LN) pstoraster $(SERVERBIN)/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: ../filter/raster.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 \ + ../filter/$(LIBCUPSIMAGE) $(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..7adae17ded --- /dev/null +++ b/pstoraster/bfont.h @@ -0,0 +1,76 @@ +/* Copyright (C) 1992, 1995, 1996, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Interpreter internal routines and data needed for building fonts */ +/* Requires gxfont.h */ + +#ifndef bfont_INCLUDED +# define bfont_INCLUDED + +#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; + +/* Options for collecting parameters from a font dictionary. */ +/* The comment indicates where the option is tested. */ +typedef enum { + bf_options_none = 0, + bf_Encoding_optional = 1, /* build_gs_font */ + bf_FontBBox_required = 2, /* build_gs_simple_font */ + bf_UniqueID_ignored = 4, /* build_gs_simple_font */ + bf_CharStrings_optional = 8, /* build_gs_primitive_font */ + bf_notdef_required = 16 /* build_gs_primitive_font */ +} build_font_options_t; + +/* In zfont2.c */ +int build_proc_name_refs(P3(build_proc_refs * pbuild, + const char *bcstr, + const char *bgstr)); +int build_gs_font_procs(P2(os_ptr, build_proc_refs *)); +int build_gs_primitive_font(P6(os_ptr, gs_font_base **, font_type, + gs_memory_type_ptr_t, const build_proc_refs *, + build_font_options_t)); +int build_gs_simple_font(P6(os_ptr, gs_font_base **, font_type, + gs_memory_type_ptr_t, const build_proc_refs *, + build_font_options_t)); +void lookup_gs_simple_font_encoding(P1(gs_font_base *)); +int build_gs_font(P6(os_ptr, gs_font **, font_type, + gs_memory_type_ptr_t, const build_proc_refs *, + build_font_options_t)); +int define_gs_font(P1(gs_font *)); + +#endif /* bfont_INCLUDED */ 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..ac798ef9cf --- /dev/null +++ b/pstoraster/btoken.h @@ -0,0 +1,41 @@ +/* Copyright (C) 1990, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Definitions for Level 2 binary tokens */ + +#ifndef btoken_INCLUDED +# define btoken_INCLUDED + +/* Define accessors for pointers to the system and user name tables. */ +extern ref binary_token_names; /* array of size 2 */ + +#define system_names_p (binary_token_names.value.refs) +#define user_names_p (binary_token_names.value.refs + 1) + +/* Convert an object to its representation in a binary object sequence. */ +int encode_binary_token(P4(const ref * obj, long *ref_offset, long *char_offset, + byte * str)); + +#endif /* btoken_INCLUDED */ diff --git a/pstoraster/ctype_.h b/pstoraster/ctype_.h new file mode 100644 index 0000000000..c120d647fe --- /dev/null +++ b/pstoraster/ctype_.h @@ -0,0 +1,37 @@ +/* Copyright (C) 1993, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Wrapper for ctype.h */ + +#ifndef ctype__INCLUDED +# define ctype__INCLUDED + +/* 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 + +#endif /* ctype__INCLUDED */ diff --git a/pstoraster/dirent_.h b/pstoraster/dirent_.h new file mode 100644 index 0000000000..4248f12cf1 --- /dev/null +++ b/pstoraster/dirent_.h @@ -0,0 +1,60 @@ +/* + Copyright 1993-2000 by Easy Software Products. + Copyright 1993, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Generic substitute for Unix dirent.h */ + +#ifndef dirent__INCLUDED +# define dirent__INCLUDED + +/* 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 /* sys/ndir or ndir or sys/dir, i.e., no dirent */ +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +typedef struct direct dir_entry; + +#endif /* sys/ndir or ndir or sys/dir */ + +#endif /* dirent__INCLUDED */ diff --git a/pstoraster/dstack.h b/pstoraster/dstack.h new file mode 100644 index 0000000000..a9480a9e98 --- /dev/null +++ b/pstoraster/dstack.h @@ -0,0 +1,236 @@ +/* Copyright (C) 1992, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Definitions for the interpreter's dictionary stack */ + +#ifndef dstack_INCLUDED +# define dstack_INCLUDED + +#include "idstack.h" + +/* Define the (currently static) dictionary stack instance. */ +extern dict_stack_t idict_stack; + +#define d_stack (idict_stack.stack) + +/* Define the interpreter-specific versions of the generic dstack API. */ +#define min_dstack_size (idict_stack.min_size) +#define dstack_userdict_index (idict_stack.userdict_index) +#define dsspace (idict_stack.def_space) +#define dtop_can_store(pvalue) ((int)r_space(pvalue) <= dsspace) +#define dtop_keys (idict_stack.top_keys) +#define dtop_npairs (idict_stack.top_npairs) +#define dtop_values (idict_stack.top_values) +#define dict_set_top() dstack_set_top(&idict_stack); +#define dict_is_permanent_on_dstack(pdict)\ + dstack_dict_is_permanent(&idict_stack, pdict) +#define dicts_gc_cleanup() dstack_gc_cleanup(&idict_stack) +#define systemdict (&idict_stack.system_dict) + +/* Define the dictionary stack pointers. */ +#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); } + +/* + * 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. + */ + +/* Name lookup */ +#define dict_find_name_by_index(nidx)\ + dstack_find_name_by_index(&idict_stack, nidx) +#define dict_find_name(pnref) dict_find_name_by_index(name_index(pnref)) +#define dict_find_name_by_index_inline(nidx, htemp)\ + dstack_find_name_by_index_inline(&idict_stack, nidx, htemp) +#define if_dict_find_name_by_index_top(nidx, htemp, pvslot)\ + if_dstack_find_name_by_index_top(&idict_stack, nidx, htemp, pvslot) + +/* + 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 + */ + +#endif /* dstack_INCLUDED */ diff --git a/pstoraster/errno_.h b/pstoraster/errno_.h new file mode 100644 index 0000000000..b2a2ae561b --- /dev/null +++ b/pstoraster/errno_.h @@ -0,0 +1,42 @@ +/* Copyright (C) 1993, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Generic substitute for Unix errno.h */ + +#ifndef errno__INCLUDED +# define errno__INCLUDED + +/* 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 + +#endif /* errno__INCLUDED */ diff --git a/pstoraster/errors.h b/pstoraster/errors.h new file mode 100644 index 0000000000..b5fd1844bc --- /dev/null +++ b/pstoraster/errors.h @@ -0,0 +1,148 @@ +/* Copyright (C) 1989, 1995, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Definition of error codes */ + +#ifndef errors_INCLUDED +# define errors_INCLUDED + +/* + * 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. + */ + +/* Define the error name table */ +extern const char *const gs_error_names[]; + + /* ------ PostScript Level 1 errors ------ */ + +#define e_unknownerror (-1) /* unknown error */ +#define e_dictfull (-2) +#define e_dictstackoverflow (-3) +#define e_dictstackunderflow (-4) +#define e_execstackoverflow (-5) +#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 +#define e_invalidaccess (-7) +#define e_invalidexit (-8) +#define e_invalidfileaccess (-9) +#define e_invalidfont (-10) +#define e_invalidrestore (-11) +#define e_ioerror (-12) +#define e_limitcheck (-13) +#define e_nocurrentpoint (-14) +#define e_rangecheck (-15) +#define e_stackoverflow (-16) +#define e_stackunderflow (-17) +#define e_syntaxerror (-18) +#define e_timeout (-19) +#define e_typecheck (-20) +#define e_undefined (-21) +#define e_undefinedfilename (-22) +#define e_undefinedresult (-23) +#define e_unmatchedmark (-24) +#define e_VMerror (-25) + +#define LEVEL1_ERROR_NAMES\ + "unknownerror", "dictfull", "dictstackoverflow", "dictstackunderflow",\ + "execstackoverflow", "interrupt", "invalidaccess", "invalidexit",\ + "invalidfileaccess", "invalidfont", "invalidrestore", "ioerror",\ + "limitcheck", "nocurrentpoint", "rangecheck", "stackoverflow",\ + "stackunderflow", "syntaxerror", "timeout", "typecheck", "undefined",\ + "undefinedfilename", "undefinedresult", "unmatchedmark", "VMerror" + + /* ------ Additional Level 2 and DPS errors ------ */ + +#define e_configurationerror (-26) +#define e_invalidcontext (-27) +#define e_undefinedresource (-28) +#define e_unregistered (-29) +/* invalidid is for the NeXT DPS extension. */ +#define e_invalidid (-30) + +#define LEVEL2_ERROR_NAMES\ + "configurationerror", "invalidcontext", "undefinedresource",\ + "unregistered", "invalidid" + +#define ERROR_NAMES LEVEL1_ERROR_NAMES, LEVEL2_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) + +#endif /* errors_INCLUDED */ diff --git a/pstoraster/estack.h b/pstoraster/estack.h new file mode 100644 index 0000000000..2c42beace7 --- /dev/null +++ b/pstoraster/estack.h @@ -0,0 +1,139 @@ +/* Copyright (C) 1989, 1992, 1993, 1994, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Definitions for the execution stack */ + +#ifndef estack_INCLUDED +# define estack_INCLUDED + +#include "iestack.h" + +/* There's only one exec stack right now.... */ +#define esfile (iexec_stack.current_file) +#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) + +/* Define the execution stack pointers. */ +extern exec_stack_t iexec_stack; + +#define e_stack (iexec_stack.stack) +#define esbot (e_stack.bot) +#define esp (e_stack.p) +#define estop (e_stack.top) + +/* + * 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 whatever state + * they need to save or keep track of and then 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 because of an error, stop, exit, + * or quit. (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 operators that need to be handled like + * looping operators -- for example, all the 'show' operators, 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) +#define set_estack_mark_index(ep, es_idx) r_set_size(ep, es_idx) + +/* 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 e-stack, must take this into account. These are: + * exit .stop .instopped countexecstack execstack currentfile + * .execn + * 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. + */ + +#endif /* estack_INCLUDED */ diff --git a/pstoraster/files.h b/pstoraster/files.h new file mode 100644 index 0000000000..bca695d4cd --- /dev/null +++ b/pstoraster/files.h @@ -0,0 +1,157 @@ +/* Copyright (C) 1989, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Requires stream.h */ + +#ifndef files_INCLUDED +# define files_INCLUDED + +/* + * 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; + +/* Export the stdio refs for switching contexts. */ +extern ref ref_stdio[3]; + +#define ref_stdin ref_stdio[0] +#define ref_stdout ref_stdio[1] +#define ref_stderr ref_stdio[2] +/* An invalid (closed) file. */ +extern stream *invalid_file_entry; + +/* + * Macros for checking file validity. + * NOTE: in order to work around a bug in the Borland 5.0 compiler, + * you must use file_is_invalid rather than !file_is_valid. + */ +#define file_is_valid(svar,op)\ + (svar = fptr(op), (svar->read_id | svar->write_id) == r_size(op)) +#define file_is_invalid(svar,op)\ + (svar = fptr(op), (svar->read_id | svar->write_id) != r_size(op)) +#define check_file(svar,op)\ + BEGIN\ + check_type(*(op), t_file);\ + if ( file_is_invalid(svar, op) ) return_error(e_invalidaccess);\ + END + +/* + * 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)\ + BEGIN\ + check_read_type(*(op), t_file);\ + check_read_known_file(svar, op, return);\ + END +#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)\ + BEGIN\ + 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 BEGIN invalid_action; END; /* closed or reopened file */\ + }\ + END +int file_switch_to_write(P1(const ref *)); + +#define check_write_file(svar,op)\ + BEGIN\ + check_write_type(*(op), t_file);\ + check_write_known_file(svar, op, return);\ + END +#define check_write_known_file(svar,op,error_return)\ + BEGIN\ + svar = fptr(op);\ + if ( svar->write_id != r_size(op) )\ + { int fcode = file_switch_to_write(op);\ + if ( fcode < 0 ) error_return(fcode);\ + }\ + END + +/* Data exported by zfile.c. */ + /* for zfilter.c and ziodev.c */ +extern const uint file_default_buffer_size; + +/* Procedures exported by zfile.c. */ + /* for imainarg.c */ +FILE *lib_fopen(P1(const char *)); + + /* for imain.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 *, + 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 zfproc.c, ziodev.c */ +stream *file_alloc_stream(P2(gs_memory_t *, client_name_t)); + +/* Procedures exported by zfileio.c. */ + /* for ziodev.c */ +int zreadline_from(P5(stream *, byte *, uint, uint *, bool *)); + +#endif /* files_INCLUDED */ diff --git a/pstoraster/fname.h b/pstoraster/fname.h new file mode 100644 index 0000000000..f6eeb8c73e --- /dev/null +++ b/pstoraster/fname.h @@ -0,0 +1,54 @@ +/* Copyright (C) 1993, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Requires gxiodev.h */ + +#ifndef fname_INCLUDED +# define fname_INCLUDED + +/* + * Define a structure for representing a parsed file name, consisting of + * an IODevice name in %'s, a file name, or both. 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; + +/* Parse a file name into device and individual name. */ +int parse_file_name(P2(const ref *, parsed_file_name *)); + +/* Parse a real (non-device) file name and convert to a C string. */ +int parse_real_file_name(P3(const ref *, parsed_file_name *, client_name_t)); + +/* Convert a file name to a C string by adding a null terminator. */ +int terminate_file_name(P2(parsed_file_name *, client_name_t)); + +/* Free a file name that was copied to a C string. */ +void free_file_name(P2(parsed_file_name *, client_name_t)); + +#endif /* fname_INCLUDED */ diff --git a/pstoraster/gconf.h b/pstoraster/gconf.h new file mode 100644 index 0000000000..0317aa9038 --- /dev/null +++ b/pstoraster/gconf.h @@ -0,0 +1,43 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Wrapper for gconfig.h or a substitute. */ + +/* + * NOTA BENE: This file, unlike all other header files, must *not* have + * double-inclusion protection, since it is used in peculiar ways. + */ + +/* + * Since not all C preprocessors implement #include with a non-quoted + * argument, we arrange things so that we can still compile with such + * compilers as long as GCONFIG_H isn't defined. + */ + +#ifndef GCONFIG_H +# include "gconfig.h" +#else +# include GCONFIG_H +#endif diff --git a/pstoraster/gconfig.c b/pstoraster/gconfig.c new file mode 100644 index 0000000000..71d5b106fb --- /dev/null +++ b/pstoraster/gconfig.c @@ -0,0 +1,127 @@ +/* Copyright (C) 1989, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Configuration tables */ +#include "memory_.h" +#include "gx.h" +#include "gscdefs.h" /* interface */ +#include "gconf.h" /* for #defines */ +#include "gxdevice.h" +#include "gxiodev.h" + +/* + * The makefile generates the file gconfig.h, which consists of + * lines of the form + * device_(gs_xxx_device) + * or + * device2_(gs_xxx_device) + * for each installed device; + * emulator_("emulator", strlen("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", strlen("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 device2_(dev) extern const gx_device dev; +#define init_(proc) extern void proc(P1(gs_memory_t *)); +#define io_device_(iodev) extern const gx_io_device iodev; +#include "gconf.h" +#undef init_ +#undef io_device_ +#undef device2_ +#undef device_ + +/* Set up the initialization procedure table. */ +extern_gx_init_table(); +private void gconf_init(P1(gs_memory_t *)); +#define init_(proc) proc, +const gx_init_proc gx_init_table[] = { +#include "gconf.h" + gconf_init, + 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, +const gx_io_device *const gx_io_device_table[] = { + &gs_iodev_os, +#include "gconf.h" + 0 +}; +#undef io_device_ +const uint gx_io_device_table_count = countof(gx_io_device_table) - 1; + +/* Set up the device table. */ +#define device_(dev) (const gx_device *)&dev, +#define device2_(dev) &dev, +private const gx_device *const gx_device_list[] = { +#include "gconf.h" + 0 +}; +#undef device2_ +#undef device_ + +/* Allocate and initialize structure descriptors for the devices. */ +private gs_memory_struct_type_t gx_device_st_list[countof(gx_device_list) - 1]; +private void +gconf_init(gs_memory_t *mem) +{ + int i; + + for (i = 0; i < countof(gx_device_list) - 1; ++i) + gx_device_make_struct_type(&gx_device_st_list[i], gx_device_list[i]); +} + +/* 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 * const **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..5f30f9ef10 --- /dev/null +++ b/pstoraster/gconfig.h @@ -0,0 +1,257 @@ +/* + * "$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-2000 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 device2_ +device2_(gs_cups_device) +device2_(gs_pswrite_device) +device2_(gs_bbox_device) +device2_(gs_nullpage_device) +#endif +#ifdef oper_ +oper_(zchar1_op_defs) +oper_(zfont1_op_defs) +oper_(zmisc1_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_type1.ps",11) +#endif +#ifdef oper_ +oper_(zvmem2_op_defs) +oper_(zdps1_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_dps1.ps",10) +#endif +#ifdef oper_ +oper_(zusparam_op_defs) +oper_(zmisc2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_lev2.ps",10) +psfile_("gs_res.ps",9) +#endif +#ifdef oper_ +oper_(zchar42_op_defs) +oper_(zfont42_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_typ42.ps",11) +psfile_("gs_cidfn.ps",11) +#endif +#ifdef oper_ +oper_(zcid_op_defs) +oper_(zcie_l2_op_defs) +oper_(zcrd_l2_op_defs) +oper_(zfcmap_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_cmap.ps",10) +#endif +#ifdef oper_ +oper_(zcfont_op_defs) +oper_(zfont0_op_defs) +# ifdef HAVE_LIBJPEG +oper_(zfdcte_op_defs) +oper_(zfdctd_op_defs) +# endif /* HAVE_LIBJPEG */ +oper_(zbseq_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_btokn.ps",11) +#endif +#ifdef init_ +init_(gs_gxicolor_init) +#endif +#ifdef oper_ +oper_(zcolor1_op_defs) +oper_(zht1_op_defs) +oper_(zupath_l2_op_defs) +oper_(ireclaim_l2_op_defs) +oper_(zchar2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_dps2.ps",10) +#endif +#ifdef oper_ +oper_(zfdecode_op_defs) +oper_(zfilter2_op_defs) +oper_(ziodev2_l2_op_defs) +#endif +#ifdef io_device_ +io_device_(gs_iodev_null) +io_device_(gs_iodev_ram) +io_device_(gs_iodev_calendar) +#endif +#ifdef oper_ +oper_(zdevice2_l2_op_defs) +oper_(zmedia2_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_setpd.ps",11) +#endif +#ifdef oper_ +oper_(zpcolor_l2_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_(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_(zimage_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) +#endif +#ifdef init_ +init_(gs_gstype1_init) +#endif +#ifdef emulator_ +emulator_("PostScript",10) +emulator_("PostScriptLevel1",16) +#endif +#ifdef init_ +init_(gs_gxi12bit_init) +init_(gs_gxiscale_init) +#endif +#ifdef oper_ +oper_(zcolor2_l2_op_defs) +oper_(zcsindex_l2_op_defs) +oper_(zht2_l2_op_defs) +oper_(zimage2_l2_op_defs) +oper_(zcssepr_l2_op_defs) +oper_(zchar32_op_defs) +oper_(zfont32_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_typ32.ps",11) +#endif +#ifdef oper_ +oper_(zfilterx_op_defs) +#endif +#ifdef emulator_ +emulator_("PostScriptLevel2",16) +#endif +#ifdef oper_ +oper_(zcspixel_op_defs) +oper_(zfunc_op_defs) +oper_(zfunc0_op_defs) +oper_(zcsdevn_op_defs) +oper_(zfreuse_op_defs) +oper_(zfunc3_op_defs) +oper_(zimage3_op_defs) +oper_(zmisc3_op_defs) +oper_(zshade_op_defs) +oper_(ztrap_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_ll3.ps",9) +#endif +#ifdef oper_ +# ifdef HAVE_LIBZ +oper_(zfzlib_op_defs) +# endif /* HAVE_LIBZ */ +#endif +#ifdef psfile_ +psfile_("gs_mex_e.ps",11) +psfile_("gs_mro_e.ps",11) +psfile_("gs_pdf_e.ps",11) +psfile_("gs_wan_e.ps",11) +psfile_("pdf_ops.ps",10) +psfile_("gs_l2img.ps",11) +psfile_("pdf_base.ps",11) +psfile_("pdf_draw.ps",11) +psfile_("pdf_font.ps",11) +psfile_("pdf_main.ps",11) +psfile_("pdf_sec.ps",10) +#endif +#ifdef emulator_ +emulator_("PDF",3) +#endif +#ifdef psfile_ +psfile_("gs_cff.ps",9) +psfile_("gs_ttf.ps",9) +#endif +#ifdef init_ +init_(gs_gstype2_init) +#endif +#ifdef io_device_ +io_device_(gs_iodev_pipe) +#endif +#ifdef psfile_ +psfile_("gs_epsf.ps",10) +#endif +#ifdef init_ +# ifdef HAVE_LIBZ +init_(gs_cl_zlib_init) +# endif /* HAVE_LIBZ */ +init_(gs_gshtscr_init) +init_(gs_gsutil_init) +init_(gs_gxcht_init) +init_(gs_gxifast_init) +init_(gs_gximono_init) +#endif +#define SEARCH_HERE_FIRST 1 + +/* + * End of "$Id$". + */ diff --git a/pstoraster/gconfig_.h b/pstoraster/gconfig_.h new file mode 100644 index 0000000000..518b790206 --- /dev/null +++ b/pstoraster/gconfig_.h @@ -0,0 +1,5 @@ +/* This file was generated automatically. */ +#define HAVE_DIRENT_H +#define HAVE_SYS_DIR_H +#define HAVE_SYS_TIME_H +#define HAVE_SYS_TIMES_H diff --git a/pstoraster/gconfigv.h b/pstoraster/gconfigv.h new file mode 100644 index 0000000000..a9ae98b88b --- /dev/null +++ b/pstoraster/gconfigv.h @@ -0,0 +1,4 @@ +#define USE_ASM (-0) +#define USE_FPU (1-0) +#define EXTEND_NAMES 0 +#define SYSTEM_CONSTANTS_ARE_WRITABLE 0 diff --git a/pstoraster/gconfxx.h b/pstoraster/gconfxx.h new file mode 100644 index 0000000000..c51a7738ba --- /dev/null +++ b/pstoraster/gconfxx.h @@ -0,0 +1,224 @@ +/* This file was generated automatically by genconf.c. */ +#ifdef device2_ +device2_(gs_cups_device) +device2_(gs_pswrite_device) +device2_(gs_bbox_device) +device2_(gs_nullpage_device) +#endif +#ifdef oper_ +oper_(zchar1_op_defs) +oper_(zfont1_op_defs) +oper_(zmisc1_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_type1.ps",11) +#endif +#ifdef oper_ +oper_(zvmem2_op_defs) +oper_(zdps1_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_dps1.ps",10) +#endif +#ifdef oper_ +oper_(zusparam_op_defs) +oper_(zmisc2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_lev2.ps",10) +psfile_("gs_res.ps",9) +#endif +#ifdef oper_ +oper_(zchar42_op_defs) +oper_(zfont42_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_typ42.ps",11) +psfile_("gs_cidfn.ps",11) +#endif +#ifdef oper_ +oper_(zcid_op_defs) +oper_(zcie_l2_op_defs) +oper_(zcrd_l2_op_defs) +oper_(zfcmap_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_cmap.ps",10) +#endif +#ifdef oper_ +oper_(zcfont_op_defs) +oper_(zfont0_op_defs) +oper_(zfdcte_op_defs) +oper_(zfdctd_op_defs) +oper_(zbseq_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_btokn.ps",11) +#endif +#ifdef init_ +init_(gs_gxicolor_init) +#endif +#ifdef oper_ +oper_(zcolor1_op_defs) +oper_(zht1_op_defs) +oper_(zupath_l2_op_defs) +oper_(ireclaim_l2_op_defs) +oper_(zchar2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_dps2.ps",10) +#endif +#ifdef oper_ +oper_(zfdecode_op_defs) +oper_(zfilter2_op_defs) +oper_(ziodev2_l2_op_defs) +#endif +#ifdef io_device_ +io_device_(gs_iodev_null) +io_device_(gs_iodev_ram) +io_device_(gs_iodev_calendar) +#endif +#ifdef oper_ +oper_(zdevice2_l2_op_defs) +oper_(zmedia2_l2_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_setpd.ps",11) +#endif +#ifdef oper_ +oper_(zpcolor_l2_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_(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_(zimage_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) +#endif +#ifdef init_ +init_(gs_gstype1_init) +#endif +#ifdef emulator_ +emulator_("PostScript",10) +emulator_("PostScriptLevel1",16) +#endif +#ifdef init_ +init_(gs_gxi12bit_init) +init_(gs_gxiscale_init) +#endif +#ifdef oper_ +oper_(zcolor2_l2_op_defs) +oper_(zcsindex_l2_op_defs) +oper_(zht2_l2_op_defs) +oper_(zimage2_l2_op_defs) +oper_(zcssepr_l2_op_defs) +oper_(zchar32_op_defs) +oper_(zfont32_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_typ32.ps",11) +#endif +#ifdef oper_ +oper_(zfilterx_op_defs) +#endif +#ifdef emulator_ +emulator_("PostScriptLevel2",16) +#endif +#ifdef oper_ +oper_(zcspixel_op_defs) +oper_(zfunc_op_defs) +oper_(zfunc0_op_defs) +oper_(zcsdevn_op_defs) +oper_(zfreuse_op_defs) +oper_(zfunc3_op_defs) +oper_(zimage3_op_defs) +oper_(zmisc3_op_defs) +oper_(zshade_op_defs) +oper_(ztrap_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_ll3.ps",9) +#endif +#ifdef oper_ +oper_(zfzlib_op_defs) +#endif +#ifdef psfile_ +psfile_("gs_mex_e.ps",11) +psfile_("gs_mro_e.ps",11) +psfile_("gs_pdf_e.ps",11) +psfile_("gs_wan_e.ps",11) +psfile_("pdf_ops.ps",10) +psfile_("gs_l2img.ps",11) +psfile_("pdf_base.ps",11) +psfile_("pdf_draw.ps",11) +psfile_("pdf_font.ps",11) +psfile_("pdf_main.ps",11) +psfile_("pdf_sec.ps",10) +#endif +#ifdef emulator_ +emulator_("PDF",3) +#endif +#ifdef psfile_ +psfile_("gs_cff.ps",9) +psfile_("gs_ttf.ps",9) +#endif +#ifdef init_ +init_(gs_gstype2_init) +#endif +#ifdef io_device_ +io_device_(gs_iodev_pipe) +#endif +#ifdef psfile_ +psfile_("gs_epsf.ps",10) +#endif +#ifdef init_ +init_(gs_cl_zlib_init) +init_(gs_gshtscr_init) +init_(gs_gsutil_init) +init_(gs_gxcht_init) +init_(gs_gxifast_init) +init_(gs_gximono_init) +#endif +#define GS_LIB_DEFAULT "/usr/local/src/espPrint/gs5.50:/usr/local/src/espPrint/gs5.50/fonts" +#define SEARCH_HERE_FIRST 1 +#define GS_DOCDIR "/usr/local/src/espPrint/gs5.50/doc" +#define GS_INIT "gs_init.ps" +#define GS_REVISION 550 +#define GS_REVISIONDATE 20000213 + diff --git a/pstoraster/gdebug.h b/pstoraster/gdebug.h new file mode 100644 index 0000000000..9b14802488 --- /dev/null +++ b/pstoraster/gdebug.h @@ -0,0 +1,132 @@ +/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Debugging machinery definitions */ + +#ifndef gdebug_INCLUDED +# define gdebug_INCLUDED + +/* + * The compile-time DEBUG symbol determines whether debugging/tracing + * code is included in the compiled code. DEBUG may be set or not set + * independently for every compilation; however, a small amount of support + * machinery in gsmisc.c is always included in the executable, just + * in case *some* file was compiled with DEBUG set. + * + * When DEBUG is set, it does not cause debugging/tracing printout to occur. + * Rather, it includes code that produces such printout *if* (a) given + * one(s) of 128 debugging flags is set. In this way, one can selectively + * turn printout on and off during debugging. (In fact, we even provide a + * PostScript operator, .setdebug, that does this.) + * + * The debugging flags are normally indexed by character code. This is more + * than a convention: gs_debug_c, which tests whether a given flag is set, + * considers that if a flag named by a given upper-case letter is set, the + * flag named by the corresponding lower-case letter is also set. + * + * If the output selected by a given flag can be printed by a single + * printf, the conventional way to produce the output is + * if_debugN('x', "...format...", v1, ..., vN); + * Usually the flag appears in the output explicitly: + * if_debugN('x', "[x]...format...", v1, ..., vN); + * If the output is more complex, the conventional way to produce the + * output is + * if ( gs_debug_c('x') ) { + * ... start each line with dlprintfN(...) + * ... produce additional output within a line with dprintfN(...) + * } */ + +/* Define the array of debugging flags, indexed by character code. */ +extern char gs_debug[128]; +bool gs_debug_c(P1(int /*char */ )); + +/* + * 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 + +/* Debugging printout macros. */ +#ifdef DEBUG +# define if_debug0(c,s)\ + BEGIN if (gs_debug_c(c)) dlprintf(s); END +# define if_debug1(c,s,a1)\ + BEGIN if (gs_debug_c(c)) dlprintf1(s,a1); END +# define if_debug2(c,s,a1,a2)\ + BEGIN if (gs_debug_c(c)) dlprintf2(s,a1,a2); END +# define if_debug3(c,s,a1,a2,a3)\ + BEGIN if (gs_debug_c(c)) dlprintf3(s,a1,a2,a3); END +# define if_debug4(c,s,a1,a2,a3,a4)\ + BEGIN if (gs_debug_c(c)) dlprintf4(s,a1,a2,a3,a4); END +# define if_debug5(c,s,a1,a2,a3,a4,a5)\ + BEGIN if (gs_debug_c(c)) dlprintf5(s,a1,a2,a3,a4,a5); END +# define if_debug6(c,s,a1,a2,a3,a4,a5,a6)\ + BEGIN if (gs_debug_c(c)) dlprintf6(s,a1,a2,a3,a4,a5,a6); END +# define if_debug7(c,s,a1,a2,a3,a4,a5,a6,a7)\ + BEGIN if (gs_debug_c(c)) dlprintf7(s,a1,a2,a3,a4,a5,a6,a7); END +# define if_debug8(c,s,a1,a2,a3,a4,a5,a6,a7,a8)\ + BEGIN if (gs_debug_c(c)) dlprintf8(s,a1,a2,a3,a4,a5,a6,a7,a8); END +# define if_debug9(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9)\ + BEGIN if (gs_debug_c(c)) dlprintf9(s,a1,a2,a3,a4,a5,a6,a7,a8,a9); END +# define if_debug10(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)\ + BEGIN if (gs_debug_c(c)) dlprintf10(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10); END +# define if_debug11(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)\ + BEGIN if (gs_debug_c(c)) dlprintf11(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11); END +# define if_debug12(c,s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)\ + BEGIN if (gs_debug_c(c)) dlprintf12(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12); END +#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/gdev8bcm.h b/pstoraster/gdev8bcm.h new file mode 100644 index 0000000000..f9f6781142 --- /dev/null +++ b/pstoraster/gdev8bcm.h @@ -0,0 +1,78 @@ +/* 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Requires gxdevice.h (for gx_color_value) */ + +#ifndef gdev8bcm_INCLUDED +# define gdev8bcm_INCLUDED + +/* + * The MS-DOS, MS Windows, and X Windows drivers all use (at least on + * some platforms) an 8-bit color map in which some fraction is reserved + * for a pre-allocated cube and some or all of the remainder is + * allocated dynamically. Since looking up colors in this map can be + * a major performance bottleneck, we provide an efficient implementation + * that can be shared among drivers. + * + * As a performance compromise, we only look up the top 5 bits of the + * RGB value in the color map. This compromises color quality very little, + * and allows substantial optimizations. + */ + +#define gx_8bit_map_size 323 +#define gx_8bit_map_spreader 123 /* approx. 323 - (1.618 * 323) */ +typedef struct gx_8bit_map_entry_s { + ushort rgb; /* key = 0rrrrrgggggbbbbb */ +#define gx_8bit_no_rgb ((ushort)0xffff) +#define gx_8bit_rgb_key(r, g, b)\ + (((r >> (gx_color_value_bits - 5)) << 10) +\ + ((g >> (gx_color_value_bits - 5)) << 5) +\ + (b >> (gx_color_value_bits - 5))) + short index; /* value */ +} gx_8bit_map_entry; +typedef struct gx_8bit_color_map_s { + int count; /* # of occupied entries */ + int max_count; /* max # of occupied entries */ + gx_8bit_map_entry map[gx_8bit_map_size + 1]; +} gx_8bit_color_map; + +/* Initialize an 8-bit color map. */ +void gx_8bit_map_init(P2(gx_8bit_color_map *, int)); + +/* Look up a color in an 8-bit color map. */ +/* Return -1 if not found. */ +int gx_8bit_map_rgb_color(P4(const gx_8bit_color_map *, gx_color_value, + gx_color_value, gx_color_value)); + +/* Test whether an 8-bit color map has room for more entries. */ +#define gx_8bit_map_is_full(pcm)\ + ((pcm)->count == (pcm)->max_count) + +/* Add a color to an 8-bit color map. */ +/* Return -1 if the map is full. */ +int gx_8bit_add_rgb_color(P4(gx_8bit_color_map *, gx_color_value, + gx_color_value, gx_color_value)); + +#endif /* gdev8bcm_INCLUDED */ diff --git a/pstoraster/gdevabuf.c b/pstoraster/gdevabuf.c new file mode 100644 index 0000000000..991584c04a --- /dev/null +++ b/pstoraster/gdevabuf.c @@ -0,0 +1,404 @@ +/* Copyright (C) 1994, 1995, 1996, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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_device_memory * const mdev = (gx_device_memory *)dev; + 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_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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); +private dev_proc_get_clipping_box(mem_abuf_get_clipping_box); + +/* The device descriptor. */ +private const gx_device_memory 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); + set_dev_proc(adev, get_clipping_box, mem_abuf_get_clipping_box); +} + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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_xyw(dev, base, sourcex, sraster, id, x, y, w, h); /* don't limit h */ + if (w <= 0 || h <= 0) + return 0; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + y_transfer yt; + + x -= mdev->mapped_x; + fit_fill_xy(dev, x, y, w, h); + fit_fill_w(dev, x, w); /* 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; +} + +/* Get the clipping box. We must scale this up by the number of alpha bits. */ +private void +mem_abuf_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + gx_device *tdev = mdev->target; + + (*dev_proc(tdev, get_clipping_box)) (tdev, pbox); + pbox->p.x <<= mdev->log2_scale.x; + pbox->p.y <<= mdev->log2_scale.y; + pbox->q.x <<= mdev->log2_scale.x; + pbox->q.y <<= mdev->log2_scale.y; +} diff --git a/pstoraster/gdevbbox.c b/pstoraster/gdevbbox.c new file mode 100644 index 0000000000..5641b36752 --- /dev/null +++ b/pstoraster/gdevbbox.c @@ -0,0 +1,1069 @@ +/* Copyright (C) 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Device for tracking bounding box */ +#include "math_.h" +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsparam.h" +#include "gxdevice.h" +#include "gsdevice.h" /* requires gsmatrix.h */ +#include "gdevbbox.h" +#include "gxdcolor.h" /* for gx_device_black/white */ +#include "gxiparam.h" /* for image source size */ +#include "gxistate.h" +#include "gxpaint.h" +#include "gxpath.h" +#include "gxcpath.h" + +/* GC descriptor */ +public_st_device_bbox(); + +/* Device procedures */ +private dev_proc_open_device(bbox_open_device); +private dev_proc_close_device(bbox_close_device); +private dev_proc_output_page(bbox_output_page); +private dev_proc_fill_rectangle(bbox_fill_rectangle); +private dev_proc_copy_mono(bbox_copy_mono); +private dev_proc_copy_color(bbox_copy_color); +private dev_proc_get_params(bbox_get_params); +private dev_proc_put_params(bbox_put_params); +private dev_proc_copy_alpha(bbox_copy_alpha); +private dev_proc_fill_path(bbox_fill_path); +private dev_proc_stroke_path(bbox_stroke_path); +private dev_proc_fill_mask(bbox_fill_mask); +private dev_proc_fill_trapezoid(bbox_fill_trapezoid); +private dev_proc_fill_parallelogram(bbox_fill_parallelogram); +private dev_proc_fill_triangle(bbox_fill_triangle); +private dev_proc_draw_thin_line(bbox_draw_thin_line); +private dev_proc_strip_tile_rectangle(bbox_strip_tile_rectangle); +private dev_proc_strip_copy_rop(bbox_strip_copy_rop); +private dev_proc_begin_typed_image(bbox_begin_typed_image); +private dev_proc_create_compositor(bbox_create_compositor); +private dev_proc_text_begin(bbox_text_begin); + +/* The device prototype */ +/* + * Normally this would be private, but if the device is going to be used + * stand-alone, it has to be public. + */ +/*private */ const +/* + * The bbox device sets the resolution to some value R (currently 4000), and + * the page size in device pixels to slightly smaller than the largest + * representable values (around 500K), leaving a little room for stroke + * widths, rounding, etc. If an input file (or the command line) resets the + * resolution to a value R' > R, the page size in pixels will get multiplied + * by R'/R, and will thereby exceed the representable range, causing a + * limitcheck. That is why the bbox device must set the resolution to a + * value larger than that of any real device. A consequence of this is that + * the page size in inches is limited to the maximum representable pixel + * size divided by R, which gives a limit of about 120" in each dimension. + */ +#define max_coord (max_int_in_fixed - 1000) +#define max_resolution 4000 +gx_device_bbox far_data gs_bbox_device = +{ + std_device_std_body(gx_device_bbox, 0, "bbox", + max_coord, max_coord, + max_resolution, max_resolution), + {bbox_open_device, + NULL, /* get_initial_matrix */ + NULL, /* sync_output */ + bbox_output_page, + bbox_close_device, + NULL, /* map_rgb_color */ + NULL, /* map_color_rgb */ + bbox_fill_rectangle, + NULL, /* tile_rectangle */ + bbox_copy_mono, + bbox_copy_color, + NULL, /* draw_line */ + NULL, /* get_bits */ + bbox_get_params, + bbox_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 */ + bbox_copy_alpha, + NULL, /* get_band */ + NULL, /* copy_rop */ + bbox_fill_path, + bbox_stroke_path, + bbox_fill_mask, + bbox_fill_trapezoid, + bbox_fill_parallelogram, + bbox_fill_triangle, + bbox_draw_thin_line, + gx_default_begin_image, + NULL, /* image_data */ + NULL, /* end_image */ + bbox_strip_tile_rectangle, + bbox_strip_copy_rop, + NULL, /* get_clipping_box */ + bbox_begin_typed_image, + NULL, /* get_bits_rectangle */ + NULL, /* map_color_rgb_alpha */ + bbox_create_compositor, + NULL, /* get_hardware_params */ + bbox_text_begin + }, + 0, /* target */ + 1 /*true *//* free_standing */ +}; + +#undef max_coord +#undef max_resolution + +/* Copy device parameters back from the target. */ +private void +bbox_copy_params(gx_device_bbox * bdev, bool remap_white) +{ + gx_device *tdev = bdev->target; + + if (tdev != 0) + gx_device_copy_params((gx_device *)bdev, tdev); + if (remap_white) + bdev->white = gx_device_white((gx_device *)bdev); +} + +#define gx_dc_is_white(pdevc, bdev)\ + (gx_dc_is_pure(pdevc) && gx_dc_pure_color(pdevc) == (bdev)->white) + +private int +bbox_close_device(gx_device * dev) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *tdev = bdev->target; + + if ((gx_device *) bdev->box_device != dev) { + /* + * This device was created as a wrapper for a compositor. + * Just free the devices. + */ + int code = (*dev_proc(tdev, close_device)) (tdev); + + gs_free_object(dev->memory, dev, "bbox_close_device(composite)"); + return code; + } else { + return (tdev == 0 ? 0 : (*dev_proc(tdev, close_device)) (tdev)); + } +} + +/* Bounding box utilities */ + +private void near +bbox_initialize(gs_fixed_rect * pr) +{ + pr->p.x = pr->p.y = max_fixed; + pr->q.x = pr->q.y = min_fixed; +} + +private void near +bbox_add_rect(gs_fixed_rect * pr, fixed x0, fixed y0, fixed x1, fixed y1) +{ + if (x0 < pr->p.x) + pr->p.x = x0; + if (y0 < pr->p.y) + pr->p.y = y0; + if (x1 > pr->q.x) + pr->q.x = x1; + if (y1 > pr->q.y) + pr->q.y = y1; +} +private void near +bbox_add_point(gs_fixed_rect * pr, fixed x, fixed y) +{ + bbox_add_rect(pr, x, y, x, y); +} +private void near +bbox_add_int_rect(gs_fixed_rect * pr, int x0, int y0, int x1, int y1) +{ + bbox_add_rect(pr, int2fixed(x0), int2fixed(y0), int2fixed(x1), + int2fixed(y1)); +} + +#define rect_is_page(dev, x, y, w, h)\ + (x <= 0 && y <= 0 && w >= x + dev->width && h >= y + dev->height) + + /* ---------------- Open/close/page ---------------- */ + +/* Initialize a bounding box device. */ +void +gx_device_bbox_init(gx_device_bbox * dev, gx_device * target) +{ + gx_device_init((gx_device *) dev, (const gx_device *)&gs_bbox_device, + (target ? target->memory : NULL), true); + gx_device_forward_fill_in_procs((gx_device_forward *) dev); + dev->target = target; + dev->box_device = dev; + bbox_copy_params(dev, false); + dev->free_standing = false; /* being used as a component */ +} + +/* Read back the bounding box in 1/72" units. */ +void +gx_device_bbox_bbox(gx_device_bbox * dev, gs_rect * pbbox) +{ + const gx_device_bbox *bbdev = dev->box_device; + gs_matrix mat; + gs_rect dbox; + + gs_deviceinitialmatrix((gx_device *) dev, &mat); + dbox.p.x = fixed2float(bbdev->bbox.p.x); + dbox.p.y = fixed2float(bbdev->bbox.p.y); + dbox.q.x = fixed2float(bbdev->bbox.q.x); + dbox.q.y = fixed2float(bbdev->bbox.q.y); + gs_bbox_transform_inverse(&dbox, &mat, pbbox); +} + + +private int +bbox_open_device(gx_device * dev) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + + if (bdev->free_standing) { + gx_device_forward_fill_in_procs((gx_device_forward *) dev); + bdev->box_device = bdev; + } + if (bdev->box_device == bdev) + bbox_initialize(&bdev->bbox); + /* gx_forward_open_device doesn't exist */ + { + gx_device *tdev = bdev->target; + int code = (tdev == 0 ? 0 : (*dev_proc(tdev, open_device)) (tdev)); + + bbox_copy_params(bdev, true); + return code; + } +} + +private int +bbox_output_page(gx_device * dev, int num_copies, int flush) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + + if (bdev->free_standing) { + /* + * This is a free-standing device. Print the page bounding box. + */ + gs_rect bbox; + + gx_device_bbox_bbox(bdev, &bbox); + dlprintf4("%%%%BoundingBox: %d %d %d %d\n", + (int)floor(bbox.p.x), (int)floor(bbox.p.y), + (int)ceil(bbox.q.x), (int)ceil(bbox.q.y)); + dlprintf4("%%%%HiResBoundingBox: %f %f %f %f\n", + bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y); + } + /* + * Propagate the PageCount to the target, + * since it changes every time gs_output_page is called. + */ + if (bdev->target) + bdev->target->PageCount = dev->PageCount; + return gx_forward_output_page(dev, num_copies, flush); +} + +/* ---------------- Low-level drawing ---------------- */ + +private int +bbox_fill_rectangle(gx_device * dev, int x, int y, int w, int h, + gx_color_index color) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device_bbox *bbdev = bdev->box_device; + + /* Check for erasing the entire page. */ + if (rect_is_page(dev, x, y, w, h)) + bbox_initialize(&bbdev->bbox); + else if (color != bdev->white) + bbox_add_int_rect(&bbdev->bbox, x, y, x + w, y + h); + /* gx_forward_fill_rectangle doesn't exist */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, fill_rectangle)) (tdev, x, y, w, h, color)); + } +} + +private int +bbox_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) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device_bbox *bbdev = bdev->box_device; + + if ((one != gx_no_color_index && one != bdev->white) || + (zero != gx_no_color_index && zero != bdev->white) + ) + bbox_add_int_rect(&bbdev->bbox, x, y, x + w, y + h); + /* gx_forward_copy_mono doesn't exist */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, copy_mono)) + (tdev, data, dx, raster, id, x, y, w, h, zero, one)); + } +} + +private int +bbox_copy_color(gx_device * dev, const byte * data, + int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_int_rect(&bbdev->bbox, x, y, x + w, y + h); + /* gx_forward_copy_color doesn't exist */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, copy_color)) + (tdev, data, dx, raster, id, x, y, w, h)); + } +} + +private int +bbox_copy_alpha(gx_device * dev, const byte * data, int data_x, + int raster, gx_bitmap_id id, int x, int y, int w, int h, + gx_color_index color, int depth) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_int_rect(&bbdev->bbox, x, y, x + w, y + h); + /* gx_forward_copy_alpha doesn't exist */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, copy_alpha)) + (tdev, data, data_x, raster, id, x, y, w, h, color, depth)); + } +} + +private int +bbox_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_bbox *const bdev = (gx_device_bbox *) dev; + gx_device_bbox *bbdev = bdev->box_device; + + if (rect_is_page(dev, x, y, w, h)) + bbox_initialize(&bbdev->bbox); + else + bbox_add_int_rect(&bbdev->bbox, x, y, x + w, y + h); + /* Skip the call if there is no target. */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, strip_tile_rectangle)) + (tdev, tiles, x, y, w, h, color0, color1, px, py)); + } +} + +private int +bbox_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 w, int h, + int phase_x, int phase_y, gs_logical_operation_t lop) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_int_rect(&bbdev->bbox, x, y, x + w, y + h); + /* gx_forward_strip_copy_rop doesn't exist */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, strip_copy_rop)) + (tdev, sdata, sourcex, sraster, id, scolors, + textures, tcolors, x, y, w, h, phase_x, phase_y, lop)); + } +} + +/* ---------------- Parameters ---------------- */ + +/* We implement get_params to provide a way to read out the bounding box. */ +private int +bbox_get_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + const gx_device_bbox *bbdev = bdev->box_device; + int code = gx_forward_get_params(dev, plist); + gs_param_float_array bba; + float bbox[4]; + + if (code < 0) + return code; + /* + * We might be calling get_params before the device has been + * initialized: in this case, bbdev = 0. + */ + if (bbdev == 0) + bbdev = (const gx_device_bbox *)dev; + bbox[0] = fixed2float(bbdev->bbox.p.x); + bbox[1] = fixed2float(bbdev->bbox.p.y); + bbox[2] = fixed2float(bbdev->bbox.q.x); + bbox[3] = fixed2float(bbdev->bbox.q.y); + bba.data = bbox, bba.size = 4, bba.persistent = false; + return param_write_float_array(plist, "PageBoundingBox", &bba); +} + +/* We implement put_params to ensure that we keep the important */ +/* device parameters up to date, and to prevent an /undefined error */ +/* from PageBoundingBox. */ +private int +bbox_put_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + int code; + int ecode = 0; + gs_param_name param_name; + gs_param_float_array bba; + + code = param_read_float_array(plist, (param_name = "PageBoundingBox"), + &bba); + switch (code) { + case 0: + if (bba.size != 4) { + ecode = gs_note_error(gs_error_rangecheck); + goto e; + } + break; + default: + ecode = code; + e:param_signal_error(plist, param_name, ecode); + case 1: + bba.data = 0; + } + + code = gx_forward_put_params(dev, plist); + if (ecode < 0) + code = ecode; + if (code >= 0 && bba.data != 0) { + gx_device_bbox *bbdev = bdev->box_device; + + bbdev->bbox.p.x = float2fixed(bba.data[0]); + bbdev->bbox.p.y = float2fixed(bba.data[1]); + bbdev->bbox.q.x = float2fixed(bba.data[2]); + bbdev->bbox.q.y = float2fixed(bba.data[3]); + } + bbox_copy_params(bdev, true); + return code; +} + +/* ---------------- Polygon drawing ---------------- */ + +private fixed +edge_x_at_y(const gs_fixed_edge * edge, fixed y) +{ + return fixed_mult_quo(edge->end.x - edge->start.x, + y - edge->start.y, + edge->end.y - edge->start.y) + edge->start.x; +} +private int +bbox_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) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + + if (!gx_dc_is_white(pdevc, bdev)) { + gx_device_bbox *bbdev = bdev->box_device; + fixed x0l = + (left->start.y == ybot ? left->start.x : + edge_x_at_y(left, ybot)); + fixed x1l = + (left->end.y == ytop ? left->end.x : + edge_x_at_y(left, ytop)); + fixed x0r = + (right->start.y == ybot ? right->start.x : + edge_x_at_y(right, ybot)); + fixed x1r = + (right->end.y == ytop ? right->end.x : + edge_x_at_y(right, ytop)); + fixed xminl = min(x0l, x1l), xmaxl = max(x0l, x1l); + fixed xminr = min(x0r, x1r), xmaxr = max(x0r, x1r); + fixed x0 = min(xminl, xminr), x1 = max(xmaxl, xmaxr); + + if (swap_axes) + bbox_add_rect(&bbdev->bbox, ybot, x0, ytop, x1); + else + bbox_add_rect(&bbdev->bbox, x0, ybot, x1, ytop); + } + /* Skip the call if there is no target. */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, fill_trapezoid)) + (tdev, left, right, ybot, ytop, swap_axes, pdevc, lop)); + } +} + +private int +bbox_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) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + + if (!gx_dc_is_white(pdevc, bdev)) { + gx_device_bbox *bbdev = bdev->box_device; + fixed pax = px + ax, pay = py + ay; + + bbox_add_rect(&bbdev->bbox, px, py, px + bx, py + by); + bbox_add_rect(&bbdev->bbox, pax, pay, pax + bx, pay + by); + } + /* Skip the call if there is no target. */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, fill_parallelogram)) + (tdev, px, py, ax, ay, bx, by, pdevc, lop)); + } +} + +private int +bbox_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) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + + if (!gx_dc_is_white(pdevc, bdev)) { + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_rect(&bbdev->bbox, px, py, px + bx, py + by); + bbox_add_point(&bbdev->bbox, px + ax, py + ay); + } + /* Skip the call if there is no target. */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, fill_triangle)) + (tdev, px, py, ax, ay, bx, by, pdevc, lop)); + } +} + +private int +bbox_draw_thin_line(gx_device * dev, + fixed fx0, fixed fy0, fixed fx1, fixed fy1, + const gx_device_color * pdevc, gs_logical_operation_t lop) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + + if (!gx_dc_is_white(pdevc, bdev)) { + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_rect(&bbdev->bbox, fx0, fy0, fx1, fy1); + } + /* Skip the call if there is no target. */ + { + gx_device *tdev = bdev->target; + + return (tdev == 0 ? 0 : + (*dev_proc(tdev, draw_thin_line)) + (tdev, fx0, fy0, fx1, fy0, pdevc, lop)); + } +} + +/* ---------------- High-level drawing ---------------- */ + +#define adjust_box(pbox, adj)\ +((pbox)->p.x -= (adj).x, (pbox)->p.y -= (adj).y,\ + (pbox)->q.x += (adj).x, (pbox)->q.y += (adj).y) + +private int +bbox_fill_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath, + const gx_fill_params * params, const gx_device_color * pdevc, + const gx_clip_path * pcpath) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *tdev = bdev->target; + + if (!gx_dc_is_white(pdevc, bdev)) { + gs_fixed_rect ibox; + gs_fixed_point adjust; + + if (gx_path_bbox(ppath, &ibox) < 0) + return 0; + adjust = params->adjust; + if (params->fill_zero_width) + gx_adjust_if_empty(&ibox, &adjust); + adjust_box(&ibox, adjust); + if (pcpath != NULL && + !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, + ibox.q.x, ibox.q.y) + ) { + /* Let the target do the drawing, but break down the */ + /* fill path into pieces for computing the bounding box. */ + bdev->target = NULL; + gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath); + bdev->target = tdev; + } else { /* Just use the path bounding box. */ + bbox_add_rect(&bdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x, + ibox.q.y); + } + } + /* Skip the call if there is no target. */ + return (tdev == 0 ? 0 : + (*dev_proc(tdev, fill_path)) + (tdev, pis, ppath, params, pdevc, pcpath)); +} + +private int +bbox_stroke_path(gx_device * dev, const gs_imager_state * pis, gx_path * ppath, + const gx_stroke_params * params, + const gx_drawing_color * pdevc, const gx_clip_path * pcpath) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *tdev = bdev->target; + + if (!gx_dc_is_white(pdevc, bdev)) { + gs_fixed_rect ibox; + gs_fixed_point expand; + + if (gx_path_bbox(ppath, &ibox) < 0) + return 0; + if (gx_stroke_path_expansion(pis, ppath, &expand) < 0) + ibox.p.x = ibox.p.y = min_fixed, ibox.q.x = ibox.q.y = max_fixed; + else + adjust_box(&ibox, expand); + if (pcpath != NULL && + !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, + ibox.q.x, ibox.q.y) + ) { + /* Let the target do the drawing, but break down the */ + /* fill path into pieces for computing the bounding box. */ + bdev->target = NULL; + gx_default_stroke_path(dev, pis, ppath, params, pdevc, pcpath); + bdev->target = tdev; + } else { + /* Just use the path bounding box. */ + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_rect(&bbdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x, + ibox.q.y); + } + } + /* Skip the call if there is no target. */ + return (tdev == 0 ? 0 : + (*dev_proc(tdev, stroke_path)) + (tdev, pis, ppath, params, pdevc, pcpath)); +} + +private int +bbox_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_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *tdev = bdev->target; + + if (pcpath != NULL && + !gx_cpath_includes_rectangle(pcpath, int2fixed(x), int2fixed(y), + int2fixed(x + w), + int2fixed(y + h)) + ) { + /* Let the target do the drawing, but break down the */ + /* image into pieces for computing the bounding box. */ + bdev->target = NULL; + gx_default_fill_mask(dev, data, dx, raster, id, x, y, w, h, + pdcolor, depth, lop, pcpath); + bdev->target = tdev; + } else { + /* Just use the mask bounding box. */ + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_int_rect(&bbdev->bbox, x, y, x + w, y + h); + } + /* Skip the call if there is no target. */ + return (tdev == 0 ? 0 : + (*dev_proc(tdev, fill_mask)) + (tdev, data, dx, raster, id, x, y, w, h, + pdcolor, depth, lop, pcpath)); +} + +/* ------ Bitmap imaging ------ */ + +typedef struct bbox_image_enum_s { + gx_image_enum_common; + gs_memory_t *memory; + gs_matrix matrix; /* map from image space to device space */ + const gx_clip_path *pcpath; + gx_image_enum_common_t *target_info; + int x0, x1; + int y, height; +} bbox_image_enum; + +gs_private_st_ptrs2(st_bbox_image_enum, bbox_image_enum, "bbox_image_enum", +bbox_image_enum_enum_ptrs, bbox_image_enum_reloc_ptrs, pcpath, target_info); + +private image_enum_proc_plane_data(bbox_image_plane_data); +private image_enum_proc_end_image(bbox_image_end_image); +private const gx_image_enum_procs_t bbox_image_enum_procs = +{ + bbox_image_plane_data, bbox_image_end_image +}; + +private int +bbox_image_begin(const gs_imager_state * pis, const gs_matrix * pmat, + const gs_image_common_t * pic, const gs_int_rect * prect, + const gx_clip_path * pcpath, gs_memory_t * memory, + bbox_image_enum ** ppbe) +{ + int code; + gs_matrix mat; + bbox_image_enum *pbe; + + if (pmat == 0) + pmat = &ctm_only(pis); + if ((code = gs_matrix_invert(&pic->ImageMatrix, &mat)) < 0 || + (code = gs_matrix_multiply(&mat, pmat, &mat)) < 0 + ) + return code; + pbe = gs_alloc_struct(memory, bbox_image_enum, &st_bbox_image_enum, + "bbox_image_begin"); + if (pbe == 0) + return_error(gs_error_VMerror); + pbe->memory = memory; + pbe->matrix = mat; + pbe->pcpath = pcpath; + pbe->target_info = 0; /* in case no target */ + if (prect) { + pbe->x0 = prect->p.x, pbe->x1 = prect->q.x; + pbe->y = prect->p.y, pbe->height = prect->q.y - prect->p.y; + } else { + gs_int_point size; + int code = (*pic->type->source_size) (pis, pic, &size); + + if (code < 0) { + gs_free_object(memory, pbe, "bbox_image_begin"); + return code; + } + pbe->x0 = 0, pbe->x1 = size.x; + pbe->y = 0, pbe->height = size.y; + } + *ppbe = pbe; + return 0; +} + +private void +bbox_image_copy_target_info(bbox_image_enum * pbe, gx_device_bbox * dev) +{ + const gx_image_enum_common_t *target_info = pbe->target_info; + + pbe->num_planes = target_info->num_planes; + memcpy(pbe->plane_depths, target_info->plane_depths, + pbe->num_planes * sizeof(pbe->plane_depths[0])); + if (dev->target == 0) { + gx_image_end(pbe->target_info, false); + pbe->target_info = 0; + } +} + +private int +bbox_begin_typed_image(gx_device * dev, + const gs_imager_state * pis, const gs_matrix * pmat, + const gs_image_common_t * pic, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, + const gx_clip_path * pcpath, + gs_memory_t * memory, gx_image_enum_common_t ** pinfo) +{ + bbox_image_enum *pbe; + int code = + bbox_image_begin(pis, pmat, pic, prect, pcpath, memory, &pbe); + + if (code < 0) + return code; + /* We fill in num_planes and plane_depths later. */ + /* format is irrelevant. */ + code = gx_image_enum_common_init((gx_image_enum_common_t *) pbe, pic, + &bbox_image_enum_procs, dev, + 0, 0, gs_image_format_chunky); + if (code < 0) + return code; + *pinfo = (gx_image_enum_common_t *) pbe; + /* + * If there is no target, we still have to call default_begin_image + * to get the correct num_planes and plane_depths. + */ + { + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *tdev = bdev->target; + + dev_proc_begin_typed_image((*begin_typed_image)); + + if (tdev == 0) { + tdev = dev; + begin_typed_image = gx_default_begin_typed_image; + } else { + begin_typed_image = dev_proc(tdev, begin_typed_image); + } + code = (*begin_typed_image) + (tdev, pis, pmat, pic, prect, pdcolor, pcpath, memory, + &pbe->target_info); + if (code < 0) + return code; + bbox_image_copy_target_info(pbe, bdev); + } + return 0; +} + +private int +bbox_image_plane_data(gx_device * dev, + gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height) +{ + + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *tdev = bdev->target; + bbox_image_enum *pbe = (bbox_image_enum *) info; + const gx_clip_path *pcpath = pbe->pcpath; + gs_rect sbox, dbox; + gs_point corners[4]; + gs_fixed_rect ibox; + + sbox.p.x = pbe->x0; + sbox.p.y = pbe->y; + sbox.q.x = pbe->x1; + sbox.q.y = pbe->y += height; + gs_bbox_transform_only(&sbox, &pbe->matrix, corners); + gs_points_bbox(corners, &dbox); + ibox.p.x = float2fixed(dbox.p.x); + ibox.p.y = float2fixed(dbox.p.y); + ibox.q.x = float2fixed(dbox.q.x); + ibox.q.y = float2fixed(dbox.q.y); + if (pcpath != NULL && + !gx_cpath_includes_rectangle(pcpath, ibox.p.x, ibox.p.y, + ibox.q.x, ibox.q.y) + ) { + /* Let the target do the drawing, but drive two triangles */ + /* through the clipping path to get an accurate bounding box. */ + gx_device_clip cdev; + gx_drawing_color devc; + fixed x0 = float2fixed(corners[0].x), y0 = float2fixed(corners[0].y); + fixed bx2 = float2fixed(corners[2].x) - x0, by2 = float2fixed(corners[2].y) - y0; + + gx_make_clip_path_device(&cdev, pcpath); + cdev.target = dev; + (*dev_proc(&cdev, open_device)) ((gx_device *) & cdev); + color_set_pure(&devc, 0); /* any color will do */ + bdev->target = NULL; + gx_default_fill_triangle((gx_device *) & cdev, x0, y0, + float2fixed(corners[1].x) - x0, + float2fixed(corners[1].y) - y0, + bx2, by2, &devc, lop_default); + gx_default_fill_triangle((gx_device *) & cdev, x0, y0, + float2fixed(corners[3].x) - x0, + float2fixed(corners[3].y) - y0, + bx2, by2, &devc, lop_default); + bdev->target = tdev; + } else { + /* Just use the bounding box. */ + gx_device_bbox *bbdev = bdev->box_device; + + bbox_add_rect(&bbdev->bbox, ibox.p.x, ibox.p.y, ibox.q.x, ibox.q.y); + } + /* Skip the call if there is no target. */ + return (tdev == 0 ? pbe->y >= pbe->height : + gx_image_plane_data(pbe->target_info, planes, height)); +} + +private int +bbox_image_end_image(gx_device * dev, gx_image_enum_common_t * info, + bool draw_last) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + bbox_image_enum *pbe = (bbox_image_enum *) info; + void *target_info = pbe->target_info; + + /* Skip the call if there is no target. */ + gx_device *tdev = bdev->target; + int code = + (tdev == 0 ? 0 : gx_image_end(target_info, draw_last)); + + gs_free_object(pbe->memory, pbe, "bbox_end_image"); + return code; +} + +private int +bbox_create_compositor(gx_device * dev, + gx_device ** pcdev, const gs_composite_t * pcte, + const gs_imager_state * pis, gs_memory_t * memory) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *target = bdev->target; + + /* + * If there isn't a target, all we care about is the bounding box, + * so don't bother with actually compositing. + */ + if (target == 0) { + *pcdev = dev; + return 0; + } + /* + * Create a compositor for the target, and then wrap another + * bbox device around it, but still accumulating the bounding + * box in the same place. + */ + { + gx_device *cdev; + gx_device_bbox *bbcdev; + int code = (*dev_proc(target, create_compositor)) + (target, &cdev, pcte, pis, memory); + + if (code < 0) + return code; + bbcdev = gs_alloc_struct_immovable(memory, gx_device_bbox, + &st_device_bbox, + "bbox_create_compositor"); + if (bbcdev == 0) { + (*dev_proc(cdev, close_device)) (cdev); + return_error(gs_error_VMerror); + } + gx_device_bbox_init(bbcdev, target); + bbcdev->target = cdev; + bbcdev->box_device = bdev; + *pcdev = (gx_device *) bbcdev; + return 0; + } +} + +/* ------ Text imaging ------ */ + +extern_st(st_gs_text_enum); + +typedef struct bbox_text_enum_s { + gs_text_enum_common; + gs_text_enum_t *target_info; +} bbox_text_enum; + +gs_private_st_suffix_add1(st_bbox_text_enum, bbox_text_enum, "bbox_text_enum", + bbox_text_enum_enum_ptrs, bbox_text_enum_reloc_ptrs, + st_gs_text_enum, target_info); + +private text_enum_proc_process(bbox_text_process); +private text_enum_proc_set_cache(bbox_text_set_cache); +private rc_free_proc(bbox_text_free); + +private const gs_text_enum_procs_t bbox_text_procs = +{ + bbox_text_process, bbox_text_set_cache +}; + +private int +bbox_text_begin(gx_device * dev, gs_imager_state * pis, + const gs_text_params_t * text, const gs_font * font, +gx_path * path, const gx_device_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * memory, gs_text_enum_t ** ppenum) +{ + gx_device_bbox *const bdev = (gx_device_bbox *) dev; + gx_device *tdev = bdev->target; + bbox_text_enum *pbte; + int code; + + if (tdev == 0) + return gx_default_text_begin(dev, pis, text, font, path, pdcolor, + pcpath, memory, ppenum); + rc_alloc_struct_1(pbte, bbox_text_enum, &st_bbox_text_enum, memory, + return_error(gs_error_VMerror), + "bbox_text_begin"); + pbte->rc.free = bbox_text_free; + code = + (*dev_proc(tdev, text_begin)) + (tdev, pis, text, font, path, pdcolor, pcpath, memory, + &pbte->target_info); + if (code < 0) { + gs_free_object(memory, pbte, "bbox_text_begin"); + return code; + } + *(gs_text_enum_t *) pbte = *pbte->target_info; /* copy common info */ + pbte->procs = &bbox_text_procs; + *ppenum = (gs_text_enum_t *) pbte; + return code; +} + +private int +bbox_text_process(gs_text_enum_t * pte) +{ + bbox_text_enum *const pbte = (bbox_text_enum *) pte; + int code = gs_text_process(pbte->target_info); + + if (code < 0) + return code; + /* Copy back the dynamic information for the client. */ + pte->index = pbte->target_info->index; + return code; +} + +private int +bbox_text_set_cache(gs_text_enum_t * pte, const double *values, + gs_text_cache_control_t control) +{ + bbox_text_enum *const pbte = (bbox_text_enum *) pte; + gs_text_enum_t *tpte = pbte->target_info; + int code = tpte->procs->set_cache(tpte, values, control); + + if (code < 0) + return code; + /* Copy back the dynamic information for the client. */ + pte->index = tpte->index; + return code; +} + +private void +bbox_text_free(gs_memory_t * memory, void *vpte, client_name_t cname) +{ + bbox_text_enum *const pbte = (bbox_text_enum *) vpte; + + gs_text_release(pbte->target_info, cname); + rc_free_struct_only(memory, vpte, cname); +} diff --git a/pstoraster/gdevbbox.h b/pstoraster/gdevbbox.h new file mode 100644 index 0000000000..5b647347b0 --- /dev/null +++ b/pstoraster/gdevbbox.h @@ -0,0 +1,100 @@ +/* Copyright (C) 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Requires gxdevice.h */ + +#ifndef gdevbbox_INCLUDED +# define gdevbbox_INCLUDED + +/* + * This device keeps track of the per-page bounding box, and also optionally + * forwards all drawing commands to a target. It can be used either as a + * free-standing device or as a component (e.g., by the EPS writer). + * + * One way to use a bounding box device is simply to include bbox.dev in the + * value of DEVICE_DEVSn in the makefile. This produces a free-standing + * device named 'bbox' that can be selected in the usual way (-sDEVICE=bbox) + * and that prints out the bounding box at each showpage or copypage without + * doing any drawing. + * + * The other way to use a bounding box device is from C code as a component + * in a device pipeline. To set up a bounding box device that doesn't do + * any drawing: + * gx_device_bbox *bdev = + * gs_alloc_struct_immovable(some_memory, + * gx_device_bbox, &st_device_bbox, + * "some identifying string for debugging"); + * gx_device_bbox_init(bdev, NULL); + * Non-drawing bounding box devices have an "infinite" page size. + * + * To set up a bounding box device that draws to another device tdev: + * gx_device_bbox *bdev = + * gs_alloc_struct_immovable(some_memory, + * gx_device_bbox, &st_device_bbox, + * "some identifying string for debugging"); + * gx_device_bbox_init(bdev, tdev); + * Bounding box devices that draw to a real device appear to have the + * same page size as that device. + * + * To intercept the end-of-page to call a routine eop of your own, after + * setting up the device: + * dev_proc_output_page(eop); -- declare a prototype for eop + * ... + * set_dev_proc(bdev, output_page, eop); + * ... + * int eop(gx_device *dev, int num_copies, int flush) + * { gs_rect bbox; + * gx_device_bbox_bbox((gx_device_bbox *)dev, &bbox); + * << do whatever you want >> + * return gx_forward_output_page(dev, num_copies, flush); + * } + */ +#define gx_device_bbox_common\ + gx_device_forward_common;\ + bool free_standing;\ + /* In order to handle compositors, we provide a separate pointer */\ + /* to the bbox device instance that holds the actual box. */\ + gx_device_bbox *box_device;\ + /* The following are updated dynamically. */\ + gs_fixed_rect bbox;\ + gx_color_index white +typedef struct gx_device_bbox_s gx_device_bbox; +struct gx_device_bbox_s { + gx_device_bbox_common; +}; + +extern_st(st_device_bbox); +#define public_st_device_bbox() /* in gdevbbox.c */\ + gs_public_st_suffix_add1_final(st_device_bbox, gx_device_bbox,\ + "gx_device_bbox", device_bbox_enum_ptrs, device_bbox_reloc_ptrs,\ + gx_device_finalize, st_device_forward, box_device) + +/* Initialize a bounding box device. */ +void gx_device_bbox_init(P2(gx_device_bbox * dev, gx_device * target)); + +/* Read back the bounding box in 1/72" units. */ +void gx_device_bbox_bbox(P2(gx_device_bbox * dev, gs_rect * pbbox)); + +#endif /* gdevbbox_INCLUDED */ diff --git a/pstoraster/gdevcmap.h b/pstoraster/gdevcmap.h new file mode 100644 index 0000000000..abfa9266f7 --- /dev/null +++ b/pstoraster/gdevcmap.h @@ -0,0 +1,74 @@ +/* Copyright (C) 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Interface to special color mapping device */ + +#ifndef gdevcmap_INCLUDED +# define gdevcmap_INCLUDED + +/* Define the color mapping algorithms. */ +typedef enum { + + /* Don't change the color. */ + + device_cmap_identity = 0, + + /* Snap each RGB primary component to 0 or 1 individually. */ + + device_cmap_snap_to_primaries, + + /* Snap black to white, other colors to black. */ + + device_cmap_color_to_black_over_white, + + /* Convert to a gray shade of the correct brightness. */ + + device_cmap_monochrome + +} gx_device_color_mapping_method_t; + +#define device_cmap_max_method device_cmap_monochrome + +/* Define the color mapping forwarding device. */ +typedef struct gx_device_cmap_s { + gx_device_forward_common; + gx_device_color_mapping_method_t mapping_method; +} gx_device_cmap; + +extern_st(st_device_cmap); +#define public_st_device_cmap() /* in gdevcmap.c */\ + gs_public_st_suffix_add0_final(st_device_cmap, gx_device_cmap,\ + "gx_device_cmap", device_cmap_enum_ptrs, device_cmap_reloc_ptrs,\ + gx_device_finalize, st_device_forward) + +/* Initialize a color mapping device. Do this just once after allocation. */ +int gdev_cmap_init(P3(gx_device_cmap * dev, gx_device * target, + gx_device_color_mapping_method_t mapping_method)); + +/* Set the color mapping method. This may be called at any time. */ +int gdev_cmap_set_method(P2(gx_device_cmap * dev, + gx_device_color_mapping_method_t mapping_method)); + +#endif /* gdevcmap_INCLUDED */ diff --git a/pstoraster/gdevcups.c b/pstoraster/gdevcups.c new file mode 100644 index 0000000000..92085dc6b6 --- /dev/null +++ b/pstoraster/gdevcups.c @@ -0,0 +1,2351 @@ +/* + * "$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 "gsexit.h" + +#include +#include +#include +#include + + +/* + * Globals... + */ + +extern const char *cupsProfile; + + +/* + * 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_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, mk; /* Integral CMYK values */ + int tc, tm, ty; /* 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 : + 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]; + + 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 : + 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]; + + 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)); + + mk = max(ic, max(im, iy)); + if (mk > ik) + ik = ik * ik / mk; + + ic = lut_rgb_color[ic - ik]; + im = lut_rgb_color[im - ik]; + iy = lut_rgb_color[iy - ik]; + 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)); + + mk = max(ic, max(im, iy)); + if (mk > ik) + ik = ik * ik / mk; + + ic = lut_rgb_color[ic - ik]; + im = lut_rgb_color[im - ik]; + iy = lut_rgb_color[iy - ik]; + 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)); + + 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)); + + mk = max(ic, max(im, iy)); + if (mk > ik) + ik = ik * ik / mk; + + ic = lut_rgb_color[ic - ik]; + im = lut_rgb_color[im - ik]; + iy = lut_rgb_color[iy - ik]; + 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 */ + 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 : + if (cups->header.cupsColorSpace == CUPS_CSPACE_KCMYcm && + cups->header.cupsBitsPerColor == 1) + cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerColor * + cups->header.cupsWidth + 7) / 8 * 6; + else + cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerColor * + cups->header.cupsWidth + 7) / 8 * + cups->color_info.num_components; + break; + + case CUPS_ORDER_PLANAR : + cups->header.cupsBytesPerLine = (cups->header.cupsBitsPerColor * + 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, 2, + "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 */ + float m[3][3]; /* Color correction matrix */ + 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 = 8; + 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 (cupsProfile && cups->header.cupsBitsPerColor == 8) + { + fprintf(stderr, "DEBUG: Using user-defined profile \"%s\"...\n", cupsProfile); + + if (sscanf(cupsProfile, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", &d, &g, + m[0] + 0, m[0] + 1, m[0] + 2, + m[1] + 0, m[1] + 1, m[1] + 2, + m[2] + 0, m[2] + 1, m[2] + 2) != 11) + fputs("DEBUG: User-defined profile does not contain 11 integers!\n", stderr); + else + { + cupsHaveProfile = 1; + + d *= 0.001f; + g *= 0.001f; + m[0][0] *= 0.001f; + m[0][1] *= 0.001f; + m[0][2] *= 0.001f; + m[1][0] *= 0.001f; + m[1][1] *= 0.001f; + m[1][2] *= 0.001f; + m[2][0] *= 0.001f; + m[2][1] *= 0.001f; + m[2][2] *= 0.001f; + } + } + else 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; + + d = profile->density; + g = profile->gamma; + + memcpy(m, profile->matrix, sizeof(m)); + } + } + + if (cupsHaveProfile) + { + 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 * m[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 */ + } + + + 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.cupsWidth * cups->header.cupsBitsPerColor + 7) / 8; + + 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, kptr = dst, cptr = kptr + bandbytes, + mptr = cptr + bandbytes, yptr = mptr + bandbytes, + lcptr = yptr + bandbytes, lmptr = lcptr + bandbytes, + bit = 128; + x > 0; + x --, srcptr ++) + { + if (*srcptr & 0x20) + *kptr |= bit; + if (*srcptr & 0x10) + *cptr |= bit; + if (*srcptr & 0x08) + *mptr |= bit; + if (*srcptr & 0x04) + *yptr |= 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/gdevdbit.c b/pstoraster/gdevdbit.c new file mode 100644 index 0000000000..0e2180f0f3 --- /dev/null +++ b/pstoraster/gdevdbit.c @@ -0,0 +1,706 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Default device bitmap copying implementation */ +#include "gx.h" +#include "gpcheck.h" +#include "gserrors.h" +#include "gsbittab.h" +#include "gsrect.h" +#include "gsropt.h" +#include "gxdcolor.h" +#include "gxdevice.h" +#include "gxdevmem.h" +#include "gdevmem.h" +#undef mdev +#include "gxcpath.h" + +/* 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) +{ + bool invert; + gx_color_index color; + gx_device_color devc; + + fit_copy(dev, data, dx, raster, id, x, y, w, h); + if (one != gx_no_color_index) { + invert = false; + color = one; + if (zero != gx_no_color_index) { + int code = (*dev_proc(dev, fill_rectangle)) + (dev, x, y, w, h, zero); + + if (code < 0) + return code; + } + } else { + invert = true; + color = zero; + } + color_set_pure(&devc, color); + return gx_dc_default_fill_masked + (&devc, data, dx, raster, id, x, y, w, h, dev, rop3_T, invert); +} + +/* 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_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 = dev->memory; + 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_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_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] = gx_device_white(dev); + scolors[1] = gx_device_black(dev); + if (tile == 0) + colors[0] = colors[1]; /* pure color */ + /* + * We want to write only where the mask is a 1, so enable source + * transparency. We have to include S in the operation, + * otherwise S_transparent will be ignored. + */ + 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 | (rop3_S | lop_S_transparent)); + } + 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 = data + (dx >> 3); + int dx_bit = dx & 7; + int wdx = w + dx_bit; + int iy; + + for (row = data, iy = 0; iy < h; row += raster, iy++) { + int ix; + + for (ix = dx_bit; ix < wdx;) { + int i0; + uint b; + uint len; + int code; + + /* Skip 0-bits. */ + b = row[ix >> 3]; + len = byte_bit_run_length[ix & 7][b ^ 0xff]; + if (len) { + ix += ((len - 1) & 7) + 1; + continue; + } + /* Scan 1-bits. */ + i0 = ix; + for (;;) { + b = row[ix >> 3]; + len = byte_bit_run_length[ix & 7][b]; + if (!len) + break; + ix += ((len - 1) & 7) + 1; + if (ix >= wdx) { + ix = wdx; + break; + } + if (len < 8) + break; + } + /* Now color the run from i0 to ix. */ + code = (*tile_proc) + (dev, tile, i0 - dx_bit + 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; + + fit_fill_xy(dev, x, y, w, h); + +#ifdef DEBUG + if (gs_debug_c('t')) { + int ptx, pty; + const byte *ptp = tiles->data; + + dlprintf3("[t]tile %dx%d raster=%d;", + tiles->size.x, tiles->size.y, tiles->raster); + dlprintf6(" x,y=%d,%d w,h=%d,%d p=%d,%d\n", + x, y, w, h, px, py); + dlputs(""); + for (pty = 0; pty < tiles->size.y; pty++) { + dprintf(" "); + for (ptx = 0; ptx < tiles->raster; ptx++) + dprintf1("%3x", *ptp++); + } + dputc('\n'); + } +#endif + + 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. */ + } { /* + * Note: we can't do the following computations until after + * the fit_fill_xy. + */ + 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; + + 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_debug5('t', " 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 */ +} + +/* ---------------- 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; 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 = alignment_mod(data, align_bitmap_mod); + 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/gdevddrw.c b/pstoraster/gdevddrw.c new file mode 100644 index 0000000000..c02c0c1d4d --- /dev/null +++ b/pstoraster/gdevddrw.c @@ -0,0 +1,635 @@ +/* Copyright (C) 1989, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Default polygon and image drawing device procedures */ +#include "math_.h" +#include "memory_.h" +#include "gx.h" +#include "gpcheck.h" +#include "gserrors.h" +#include "gxfixed.h" +#include "gxmatrix.h" +#include "gxdcolor.h" +#include "gxdevice.h" +#include "gxiparam.h" +#include "gxistate.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 that the 'a' line is to the left of + * the 'b' line. Testing ax <= bx is neither sufficient nor + * necessary: in general, we need to compare the slopes. + */ +#define swap(r, s) (t = r, r = s, s = t) + if ((ax ^ bx) < 0) { /* In this case, the test ax <= bx is sufficient. */ + if (ax > bx) + swap(ax, bx), swap(ay, by); + } else { /* + * Compare the slopes. We know that ay >= 0, by >= 0, + * and ax and bx have the same sign; the lines are in the + * correct order iff + * ay/ax >= by/bx, or + * ay*bx >= by*ax + * Eventually we can probably find a better way to test this, + * without using floating point. + */ + if ((double)ay * bx < (double)by * ax) + 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 ay <= by. */ +#define swap(r, s) (t = r, r = s, s = t) + if (ay > by) + swap(ax, bx), swap(ay, by); +#undef swap + /* + * Make a special check for a flat bottom or top, + * which we can handle with a single call on fill_trapezoid. + */ + left.start.x = right.start.x = px; + left.start.y = right.start.y = py; + if (ay == 0) { + /* Flat top */ + if (ax < 0) + left.start.x = px + ax; + else + right.start.x = px + ax; + left.end.x = right.end.x = px + bx; + left.end.y = right.end.y = py + by; + ym = py; + } else if (ay == by) { + /* Flat bottom */ + if (ax < bx) + left.end.x = px + ax, right.end.x = px + bx; + else + left.end.x = px + bx, right.end.x = px + ax; + left.end.y = right.end.y = py + by; + ym = py; + } else { + ym = py + ay; + if (fixed_mult_quo(bx, ay, by) < ax) { + /* The 'b' line is to the left of the 'a' line. */ + left.end.x = px + bx, left.end.y = py + by; + right.end.x = px + ax, right.end.y = py + ay; + code = (*fill_trapezoid) (dev, &left, &right, py, ym, + false, pdevc, lop); + right.start = right.end; + right.end = left.end; + } else { + /* The 'a' line is to the left of the 'b' line. */ + left.end.x = px + ax, left.end.y = py + ay; + right.end.x = px + bx, right.end.y = py + by; + code = (*fill_trapezoid) (dev, &left, &right, py, ym, + false, pdevc, lop); + left.start = left.end; + left.end = right.end; + } + if (code < 0) + return code; + } + 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) + ); + } { + 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; +} + +/* ---------------- Image drawing ---------------- */ + +/* GC structures for image enumerator */ +public_st_gx_image_enum_common(); + +#define eptr ((gx_image_enum_common_t *)vptr) + +private +ENUM_PTRS_BEGIN(image_enum_common_enum_ptrs) return 0; + +case 0: +return ENUM_OBJ(gx_device_enum_ptr(eptr->dev)); +ENUM_PTRS_END + +private RELOC_PTRS_BEGIN(image_enum_common_reloc_ptrs) +{ + eptr->dev = gx_device_reloc_ptr(eptr->dev, gcst); +} +RELOC_PTRS_END + +#undef eptr + +/* + * gx_default_begin_image is only invoked for ImageType 1 images. However, + * the argument types are different, and if the device provides a + * begin_typed_image procedure, we should use it. See gxdevice.h. + */ +private int +gx_no_begin_image(gx_device * dev, + const gs_imager_state * pis, const gs_image_t * pim, + gs_image_format_t format, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * memory, gx_image_enum_common_t ** pinfo) +{ + return -1; +} +int +gx_default_begin_image(gx_device * dev, + const gs_imager_state * pis, const gs_image_t * pim, + gs_image_format_t format, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * memory, gx_image_enum_common_t ** pinfo) +{ + /* + * Hand off to begin_typed_image, being careful to avoid a + * possible recursion loop. + */ + dev_proc_begin_image((*save_begin_image)) = dev_proc(dev, begin_image); + gs_image_t image; + const gs_image_t *ptim; + int code; + + set_dev_proc(dev, begin_image, gx_no_begin_image); + if (pim->format == format) + ptim = pim; + else { + image = *pim; + image.format = format; + ptim = ℑ + } + code = (*dev_proc(dev, begin_typed_image)) + (dev, pis, NULL, (const gs_image_common_t *)ptim, prect, pdcolor, + pcpath, memory, pinfo); + set_dev_proc(dev, begin_image, save_begin_image); + return code; +} + +int +gx_default_begin_typed_image(gx_device * dev, + const gs_imager_state * pis, const gs_matrix * pmat, + const gs_image_common_t * pic, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * memory, gx_image_enum_common_t ** pinfo) +{ /* + * If this is an ImageType 1 image using the imager's CTM, + * defer to begin_image. + */ + if (pic->type->begin_typed_image == gx_begin_image1) { + const gs_image_t *pim = (const gs_image_t *)pic; + + if (pmat == 0 || + (pis != 0 && !memcmp(pmat, &ctm_only(pis), sizeof(*pmat))) + ) { + int code = (*dev_proc(dev, begin_image)) + (dev, pis, pim, pim->format, prect, pdcolor, + pcpath, memory, pinfo); + + if (code >= 0) + return code; + } + } + return (*pic->type->begin_typed_image) + (dev, pis, pmat, pic, prect, pdcolor, pcpath, memory, pinfo); +} + +int +gx_image_data(gx_image_enum_common_t * info, const byte ** plane_data, + int data_x, uint raster, int height) +{ + int num_planes = info->num_planes; + gx_image_plane_t planes[gs_image_max_components]; + int i; + +#ifdef DEBUG + if (num_planes > gs_image_max_components) { + lprintf2("num_planes=%d > gs_image_max_components=%d!\n", + num_planes, gs_image_max_components); + return_error(gs_error_Fatal); + } +#endif + for (i = 0; i < num_planes; ++i) { + planes[i].data = plane_data[i]; + planes[i].data_x = data_x; + planes[i].raster = raster; + } + return gx_image_plane_data(info, planes, height); +} + +int +gx_image_plane_data(gx_image_enum_common_t * info, + const gx_image_plane_t * planes, int height) +{ + return info->procs->plane_data(info->dev, info, planes, height); +} + +int +gx_image_end(gx_image_enum_common_t * info, bool draw_last) +{ + return info->procs->end_image(info->dev, info, draw_last); +} + +/* Backward compatibility for obsolete driver procedures. */ + +int +gx_default_image_data(gx_device *dev, gx_image_enum_common_t * info, + const byte ** plane_data, + int data_x, uint raster, int height) +{ + return gx_image_data(info, plane_data, data_x, raster, height); +} + +int +gx_default_end_image(gx_device *dev, gx_image_enum_common_t * info, + bool draw_last) +{ + return gx_image_end(info, draw_last); +} diff --git a/pstoraster/gdevdflt.c b/pstoraster/gdevdflt.c new file mode 100644 index 0000000000..7633b7b43b --- /dev/null +++ b/pstoraster/gdevdflt.c @@ -0,0 +1,270 @@ +/* Copyright (C) 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Default device implementation */ +#include "gx.h" +#include "gserrors.h" +#include "gsropt.h" +#include "gxcomp.h" +#include "gxdevice.h" +#include "gxdevmem.h" +#undef mdev + +/* ---------------- Default device procedures ---------------- */ + +/* 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, obsolete_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); + 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); + /* + * We always replace image_data and end_image with the new + * procedures, and, if in a DEBUG configuration, print a warning + * if the definitions aren't the default ones. + */ +#ifdef DEBUG +# define CHECK_NON_DEFAULT(proc, default, procname)\ + BEGIN\ + if ( dev_proc(dev, proc) != NULL && dev_proc(dev, proc) != default )\ + dprintf2("**** Warning: device %s implements obsolete procedure %s\n",\ + dev->dname, procname);\ + END +#else +# define CHECK_NON_DEFAULT(proc, default, procname)\ + DO_NOTHING +#endif + CHECK_NON_DEFAULT(image_data, gx_default_image_data, "image_data"); + set_dev_proc(dev, image_data, gx_default_image_data); + CHECK_NON_DEFAULT(end_image, gx_default_end_image, "end_image"); + set_dev_proc(dev, end_image, gx_default_end_image); +#undef CHECK_NON_DEFAULT + fill_dev_proc(dev, strip_tile_rectangle, gx_default_strip_tile_rectangle); + fill_dev_proc(dev, strip_copy_rop, gx_default_strip_copy_rop); + fill_dev_proc(dev, get_clipping_box, gx_default_get_clipping_box); + fill_dev_proc(dev, begin_typed_image, gx_default_begin_typed_image); + fill_dev_proc(dev, get_bits_rectangle, gx_default_get_bits_rectangle); + fill_dev_proc(dev, map_color_rgb_alpha, gx_default_map_color_rgb_alpha); + fill_dev_proc(dev, create_compositor, gx_default_create_compositor); + fill_dev_proc(dev, get_hardware_params, gx_default_get_hardware_params); + fill_dev_proc(dev, text_begin, gx_default_text_begin); +} + +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; +} + +const 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_default_get_band(gx_device * dev, int y, int *band_start) +{ + return 0; +} + +void +gx_default_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox) +{ + pbox->p.x = 0; + pbox->p.y = 0; + pbox->q.x = int2fixed(dev->width); + pbox->q.y = int2fixed(dev->height); +} +void +gx_get_largest_clipping_box(gx_device * dev, gs_fixed_rect * pbox) +{ + pbox->p.x = min_fixed; + pbox->p.y = min_fixed; + pbox->q.x = max_fixed; + pbox->q.y = max_fixed; +} + +int +gx_no_create_compositor(gx_device * dev, gx_device ** pcdev, + const gs_composite_t * pcte, const gs_imager_state * pis, gs_memory_t * memory) +{ + return_error(gs_error_unknownerror); /* not implemented */ +} +int +gx_default_create_compositor(gx_device * dev, gx_device ** pcdev, + const gs_composite_t * pcte, const gs_imager_state * pis, gs_memory_t * memory) +{ + return (*pcte->type->procs.create_default_compositor) + (pcte, pcdev, dev, pis, memory); +} +int +gx_non_imaging_create_compositor(gx_device * dev, gx_device ** pcdev, + const gs_composite_t * pcte, const gs_imager_state * pis, gs_memory_t * memory) +{ + *pcdev = dev; + return 0; +} + +/* 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) + assign_dev_procs(mdev, mdproto); + 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); +} diff --git a/pstoraster/gdevdgbr.c b/pstoraster/gdevdgbr.c new file mode 100644 index 0000000000..c156696950 --- /dev/null +++ b/pstoraster/gdevdgbr.c @@ -0,0 +1,586 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Default implementation of device get_bits[_rectangle] */ +#include "gx.h" +#include "gserrors.h" +#include "gxdevice.h" +#include "gxdevmem.h" +#include "gxgetbit.h" +#include "gxlum.h" +#include "gdevmem.h" + +int +gx_no_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data) +{ + return_error(gs_error_unknownerror); +} +int +gx_default_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data) +{ /* + * Hand off to get_bits_rectangle, being careful to avoid a + * possible recursion loop. + */ + dev_proc_get_bits((*save_get_bits)) = dev_proc(dev, get_bits); + gs_int_rect rect; + gs_get_bits_params_t params; + int code; + + rect.p.x = 0, rect.p.y = y; + rect.q.x = dev->width, rect.q.y = y + 1; + params.options = + (actual_data ? GB_RETURN_POINTER : 0) | GB_RETURN_COPY | + (GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_RASTER_STANDARD | + /* No depth specified, we always use native colors. */ + GB_PACKING_CHUNKY | GB_COLORS_NATIVE | GB_ALPHA_NONE); + params.x_offset = 0; + params.raster = bitmap_raster(dev->width * dev->color_info.depth); + params.data[0] = data; + set_dev_proc(dev, get_bits, gx_no_get_bits); + code = (*dev_proc(dev, get_bits_rectangle)) + (dev, &rect, ¶ms, NULL); + if (actual_data) + *actual_data = params.data[0]; + set_dev_proc(dev, get_bits, save_get_bits); + return code; +} + +/* + * Determine whether we can satisfy a request by simply using the stored + * representation. + */ +private bool +requested_includes_stored(gs_get_bits_options_t requested, + gs_get_bits_options_t stored) +{ + gs_get_bits_options_t both = requested & stored; + + if (!(both & GB_PACKING_ALL)) + return false; + if (both & GB_COLORS_NATIVE) + return true; + if (both & GB_COLORS_STANDARD_ALL) { + if ((both & GB_ALPHA_ALL) && (both & GB_DEPTH_ALL)) + return true; + } + return false; +} + +/* + * Try to implement get_bits_rectangle by returning a pointer. + * Note that dev is used only for computing the default raster + * and for color_info.depth. + * This routine does not check x or h for validity. + */ +int +gx_get_bits_return_pointer(gx_device * dev, int x, int h, + gs_get_bits_params_t * params, gs_get_bits_options_t stored, + byte * stored_base) +{ + gs_get_bits_options_t options = params->options; + + if (!(options & GB_RETURN_POINTER) || + !requested_includes_stored(options, stored) + ) + return -1; + /* + * See whether we can return the bits in place. Note that even if + * offset_any isn't set, x_offset and x don't have to be equal: their + * bit offsets only have to match modulo align_bitmap_mod * 8 (to + * preserve alignment) if align_any isn't set, or mod 8 (since + * byte alignment is always required) if align_any is set. + */ + { + int depth = dev->color_info.depth; + uint dev_raster = gx_device_raster(dev, 1); + uint raster = + (options & (GB_RASTER_STANDARD | GB_RASTER_ANY) ? dev_raster : + params->raster); + + if (h <= 1 || raster == dev_raster) { + int x_offset = + (options & GB_OFFSET_ANY ? x : + options & GB_OFFSET_0 ? 0 : params->x_offset); + + if (x_offset == x) { + params->data[0] = stored_base; + params->x_offset = x; + } else { + uint align_mod = + (options & GB_ALIGN_ANY ? 8 : align_bitmap_mod * 8); + int bit_offset = x - x_offset; + int bytes; + + if (bit_offset & (align_mod - 1)) + return -1; /* can't align */ + if (depth & (depth - 1)) { + /* step = lcm(depth, align_mod) */ + int step = depth / igcd(depth, align_mod) * align_mod; + + bytes = bit_offset / step * step; + } else { + /* Use a faster algorithm if depth is a power of 2. */ + bytes = bit_offset & (-depth & -align_mod); + } + params->data[0] = stored_base + arith_rshift(bytes, 3); + params->x_offset = (bit_offset - bytes) / depth; + } + params->options = + GB_ALIGN_STANDARD | GB_RETURN_POINTER | GB_RASTER_STANDARD | + GB_PACKING_CHUNKY | stored | + (params->x_offset == 0 ? GB_OFFSET_0 : GB_OFFSET_SPECIFIED); + return 0; + } + } + return -1; +} + +/* + * Convert pixels between representations, primarily for get_bits_rectangle. + * stored indicates how the data are actually stored, and includes: + * - one option from the GB_PACKING group; + * - if h > 1, one option from the GB_RASTER group; + * - optionally (and normally), GB_COLORS_NATIVE; + * - optionally, one option each from the GB_COLORS_STANDARD, GB_DEPTH, + * and GB_ALPHA groups. + * Note that dev is used only for color mapping. This routine assumes that + * the stored data are aligned. + * + * Note: this routine does not check x, w, h for validity. + */ +int +gx_get_bits_copy(gx_device * dev, int x, int w, int h, + gs_get_bits_params_t * params, gs_get_bits_options_t stored, + const byte * src_base, uint dev_raster) +{ + gs_get_bits_options_t options = params->options; + byte *data = params->data[0]; + int depth = dev->color_info.depth; + int bit_x = x * depth; + const byte *src = src_base; + + /* + * If the stored representation matches a requested representation, + * we can copy the data without any transformations. + */ + bool direct_copy = requested_includes_stored(options, stored); + + /* + * The request must include GB_PACKING_CHUNKY, GB_RETURN_COPY, + * and an offset and raster specification. + */ + if ((~options & (GB_PACKING_CHUNKY | GB_RETURN_COPY)) || + !(options & (GB_OFFSET_0 | GB_OFFSET_SPECIFIED)) || + !(options & (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED)) + ) + return_error(gs_error_rangecheck); + { + int x_offset = (options & GB_OFFSET_0 ? 0 : params->x_offset); + int end_bit = (x_offset + w) * depth; + uint std_raster = + (options & GB_ALIGN_STANDARD ? bitmap_raster(end_bit) : + (end_bit + 7) >> 3); + uint raster = + (options & GB_RASTER_STANDARD ? std_raster : params->raster); + int dest_bit_x = x_offset * depth; + int skew = bit_x - dest_bit_x; + + /* + * If the bit positions line up, use bytes_copy_rectangle. + * Since bytes_copy_rectangle doesn't require alignment, + * the bit positions only have to match within a byte, + * not within align_bitmap_mod bytes. + */ + if (!(skew & 7) && direct_copy) { + int bit_w = w * depth; + + bytes_copy_rectangle(data + (dest_bit_x >> 3), raster, + src + (bit_x >> 3), dev_raster, + ((bit_x + bit_w + 7) >> 3) - (bit_x >> 3), h); + } else if (direct_copy) { + /* + * Use the logic already in mem_mono_copy_mono to copy the + * bits to the destination. We do this one line at a time, + * to avoid having to allocate a line pointer table. + */ + gx_device_memory tdev; + byte *line_ptr = data; + + tdev.line_ptrs = &tdev.base; + for (; h > 0; line_ptr += raster, src += dev_raster, --h) { + /* Make sure the destination is aligned. */ + int align = alignment_mod(line_ptr, align_bitmap_mod); + + tdev.base = line_ptr - align; + (*dev_proc(&mem_mono_device, copy_mono)) + ((gx_device *) & tdev, src, bit_x, dev_raster, gx_no_bitmap_id, + dest_bit_x + (align << 3), 0, w, 1, + (gx_color_index) 0, (gx_color_index) 1); + } + } else if (options & ~stored & GB_COLORS_NATIVE) { + /* + * Convert standard colors to native. Note that the source + * may have depths other than 8 bits per component. + */ + int dest_bit_offset = x_offset * depth; + byte *dest_line = data + (dest_bit_offset >> 3); + int ncolors = + (stored & GB_COLORS_RGB ? 3 : stored & GB_COLORS_CMYK ? 4 : + stored & GB_COLORS_GRAY ? 1 : -1); + int ncomp = ncolors + + ((stored & (GB_ALPHA_FIRST | GB_ALPHA_LAST)) != 0); + int src_depth = GB_OPTIONS_DEPTH(stored); + int src_bit_offset = x * src_depth * ncomp; + const byte *src_line = src_base + (src_bit_offset >> 3); + gx_color_value src_max = (1 << src_depth) - 1; + +#define v2cv(value) ((ulong)(value) * gx_max_color_value / src_max) + gx_color_value alpha_default = src_max; + + options &= ~GB_COLORS_ALL | GB_COLORS_NATIVE; + for (; h > 0; dest_line += raster, src_line += dev_raster, --h) { + int i; + + sample_load_declare_setup(src, sbit, src_line, + src_bit_offset & 7, src_depth); + sample_store_declare_setup(dest, dbit, dbyte, dest_line, + dest_bit_offset & 7, depth); + + for (i = 0; i < w; ++i) { + int j; + gx_color_value v[4], va = alpha_default; + gx_color_index pixel; + + /* Fetch the source data. */ + if (stored & GB_ALPHA_FIRST) { + sample_load_next16(va, src, sbit, src_depth); + va = v2cv(va); + } + for (j = 0; j < ncolors; ++j) { + gx_color_value vj; + + sample_load_next16(vj, src, sbit, src_depth); + v[j] = v2cv(vj); + } + if (stored & GB_ALPHA_LAST) { + sample_load_next16(va, src, sbit, src_depth); + va = v2cv(va); + } + /* Convert and store the pixel value. */ + switch (ncolors) { + case 1: + v[2] = v[1] = v[0]; + case 3: + pixel = (*dev_proc(dev, map_rgb_alpha_color)) + (dev, v[0], v[1], v[2], va); + break; + case 4: + /****** NO ALPHA FOR CMYK ******/ + pixel = (*dev_proc(dev, map_cmyk_color)) + (dev, v[0], v[1], v[2], v[3]); + break; + default: + return_error(gs_error_rangecheck); + } + sample_store_next32(pixel, dest, dbit, depth, dbyte); + } + sample_store_flush(dest, dbit, depth, dbyte); + } + } else if (!(options & GB_DEPTH_8)) { + /* + * We don't support general depths yet, or conversion between + * different formats. Punt. + */ + return_error(gs_error_rangecheck); + } else { + /* + * We have to do some conversion to each pixel. This is the + * slowest, most general case. + */ + int src_bit_offset = x * depth; + const byte *src_line = src_base + (src_bit_offset >> 3); + int ncomp = + (options & (GB_ALPHA_FIRST | GB_ALPHA_LAST) ? 4 : 3); + byte *dest_line = data + x_offset * ncomp; + + /* Pick the representation that's most likely to be useful. */ + if (options & GB_COLORS_RGB) + options &= ~GB_COLORS_STANDARD_ALL | GB_COLORS_RGB; + else if (options & GB_COLORS_CMYK) + options &= ~GB_COLORS_STANDARD_ALL | GB_COLORS_CMYK; + else if (options & GB_COLORS_GRAY) + options &= ~GB_COLORS_STANDARD_ALL | GB_COLORS_GRAY; + else + return_error(gs_error_rangecheck); + for (; h > 0; dest_line += raster, src_line += dev_raster, --h) { + int i; + + sample_load_declare_setup(src, bit, src_line, src_bit_offset & 7, + depth); + byte *dest = dest_line; + + for (i = 0; i < w; ++i) { + gx_color_index pixel = 0; + gx_color_value rgba[4]; + + sample_load_next32(pixel, src, bit, depth); + (*dev_proc(dev, map_color_rgb_alpha)) (dev, pixel, rgba); + if (options & GB_ALPHA_FIRST) + *dest++ = gx_color_value_to_byte(rgba[3]); + /* Convert to the requested color space. */ + if (options & GB_COLORS_RGB) { + dest[0] = gx_color_value_to_byte(rgba[0]); + dest[1] = gx_color_value_to_byte(rgba[1]); + dest[2] = gx_color_value_to_byte(rgba[2]); + dest += 3; + } else if (options & GB_COLORS_CMYK) { + /* Use the standard RGB to CMYK algorithm, */ + /* with maximum black generation and undercolor removal. */ + gx_color_value white = max(rgba[0], max(rgba[1], rgba[2])); + + dest[0] = gx_color_value_to_byte(white - rgba[0]); + dest[1] = gx_color_value_to_byte(white - rgba[1]); + dest[2] = gx_color_value_to_byte(white - rgba[2]); + dest[3] = gx_color_value_to_byte(gx_max_color_value - white); + dest += 4; + } else { /* GB_COLORS_GRAY */ + /* Use the standard RGB to Gray algorithm. */ + *dest++ = gx_color_value_to_byte( + ((rgba[0] * (ulong) lum_red_weight) + + (rgba[1] * (ulong) lum_green_weight) + + (rgba[2] * (ulong) lum_blue_weight) + + (lum_all_weights / 2)) + / lum_all_weights); + } + if (options & GB_ALPHA_LAST) + *dest++ = gx_color_value_to_byte(rgba[3]); + } + } + } + params->options = + (options & (GB_COLORS_ALL | GB_ALPHA_ALL)) | GB_PACKING_CHUNKY | + (options & GB_COLORS_NATIVE ? 0 : options & GB_DEPTH_ALL) | + (options & GB_ALIGN_STANDARD ? GB_ALIGN_STANDARD : GB_ALIGN_ANY) | + GB_RETURN_COPY | + (x_offset == 0 ? GB_OFFSET_0 : GB_OFFSET_SPECIFIED) | + (raster == std_raster ? GB_RASTER_STANDARD : GB_RASTER_SPECIFIED); + } + return 0; +} + +int +gx_no_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, + gs_get_bits_params_t * params, gs_int_rect ** unread) +{ + return_error(gs_error_unknownerror); +} +int +gx_default_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, + gs_get_bits_params_t * params, gs_int_rect ** unread) +{ + dev_proc_get_bits_rectangle((*save_get_bits_rectangle)) = + dev_proc(dev, get_bits_rectangle); + int depth = dev->color_info.depth; + uint min_raster = (dev->width * depth + 7) >> 3; + gs_get_bits_options_t options = params->options; + int code; + + /* Avoid a recursion loop. */ + set_dev_proc(dev, get_bits_rectangle, gx_no_get_bits_rectangle); + /* + * If the parameters are right, try to call get_bits directly. Note + * that this may fail if a device only implements get_bits_rectangle + * (not get_bits) for a limited set of options. Note also that this + * must handle the case of the recursive call from within + * get_bits_rectangle (see below): because of this, and only because + * of this, it must handle partial scan lines. + */ + if (prect->q.y == prect->p.y + 1 && + !(~options & + (GB_RETURN_COPY | GB_PACKING_CHUNKY | GB_COLORS_NATIVE)) && + (options & (GB_ALIGN_STANDARD | GB_ALIGN_ANY)) && + ((options & (GB_OFFSET_0 | GB_OFFSET_ANY)) || + ((options & GB_OFFSET_SPECIFIED) && params->x_offset == 0)) && + ((options & (GB_RASTER_STANDARD | GB_RASTER_ANY)) || + ((options & GB_RASTER_SPECIFIED) && + params->raster >= min_raster)) && + unread == NULL + ) { + byte *data = params->data[0]; + byte *row = data; + + if (!(prect->p.x == 0 && prect->q.x == dev->width)) { + /* Allocate an intermediate row buffer. */ + row = gs_alloc_bytes(dev->memory, min_raster, + "gx_default_get_bits_rectangle"); + + if (row == 0) { + code = gs_note_error(gs_error_VMerror); + goto ret; + } + } + code = (*dev_proc(dev, get_bits)) + (dev, prect->p.y, row, ¶ms->data[0]); + if (code >= 0) { + if (row != data) { + if (prect->p.x == 0 && params->data[0] != row) { + /* + * get_bits returned an appropriate pointer: we can + * avoid doing any copying. + */ + DO_NOTHING; + } else { + /* Copy the partial row into the supplied buffer. */ + int width_bits = (prect->q.x - prect->p.x) * depth; + gx_device_memory tdev; + + tdev.width = width_bits; + tdev.height = 1; + tdev.line_ptrs = &tdev.base; + tdev.base = data; + code = (*dev_proc(&mem_mono_device, copy_mono)) + ((gx_device *) & tdev, params->data[0], prect->p.x * depth, + min_raster, gx_no_bitmap_id, 0, 0, width_bits, 1, + (gx_color_index) 0, (gx_color_index) 1); + params->data[0] = data; + } + gs_free_object(dev->memory, row, + "gx_default_get_bits_rectangle"); + } + params->options = + GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_PACKING_CHUNKY | + GB_ALPHA_NONE | GB_COLORS_NATIVE | GB_RASTER_STANDARD | + (params->data[0] == data ? GB_RETURN_COPY : GB_RETURN_POINTER); + goto ret; + } + } { + /* Do the transfer row-by-row using a buffer. */ + int x = prect->p.x, w = prect->q.x - x; + int bits_per_pixel = depth; + byte *row; + + if (options & GB_COLORS_STANDARD_ALL) { + /* + * Make sure the row buffer can hold the standard color + * representation, in case the device decides to use it. + */ + int bpc = GB_OPTIONS_MAX_DEPTH(options); + int nc = + (options & GB_COLORS_CMYK ? 4 : + options & GB_COLORS_RGB ? 3 : 1) + + (options & (GB_ALPHA_ALL - GB_ALPHA_NONE) ? 1 : 0); + int bpp = bpc * nc; + + if (bpp > bits_per_pixel) + bits_per_pixel = bpp; + } + row = gs_alloc_bytes(dev->memory, (bits_per_pixel * w + 7) >> 3, + "gx_default_get_bits_rectangle"); + if (row == 0) { + code = gs_note_error(gs_error_VMerror); + } else { + uint dev_raster = gx_device_raster(dev, true); + uint raster = + (options & GB_RASTER_SPECIFIED ? params->raster : + options & GB_ALIGN_STANDARD ? bitmap_raster(depth * w) : + (depth * w + 7) >> 3); + gs_int_rect rect; + gs_get_bits_params_t copy_params; + gs_get_bits_options_t copy_options = + GB_ALIGN_ANY | (GB_RETURN_COPY | GB_RETURN_POINTER) | + (GB_OFFSET_0 | GB_OFFSET_ANY) | + (GB_RASTER_STANDARD | GB_RASTER_ANY) | GB_PACKING_CHUNKY | + GB_COLORS_NATIVE | (options & (GB_DEPTH_ALL | GB_COLORS_ALL)) | + GB_ALPHA_ALL; + byte *dest = params->data[0]; + int y; + + rect.p.x = x, rect.q.x = x + w; + code = 0; + for (y = prect->p.y; y < prect->q.y; ++y) { + rect.p.y = y, rect.q.y = y + 1; + copy_params.options = copy_options; + copy_params.data[0] = row; + code = (*save_get_bits_rectangle) + (dev, &rect, ©_params, NULL); + if (code < 0) + break; + if (copy_params.options & GB_OFFSET_0) + copy_params.x_offset = 0; + params->data[0] = dest + (y - prect->p.y) * raster; + code = gx_get_bits_copy(dev, copy_params.x_offset, w, 1, + params, copy_params.options, + copy_params.data[0], dev_raster); + if (code < 0) + break; + } + gs_free_object(dev->memory, row, "gx_default_get_bits_rectangle"); + params->data[0] = dest; + } + } + ret:set_dev_proc(dev, get_bits_rectangle, save_get_bits_rectangle); + return (code < 0 ? code : 0); +} + +/* ------ Debugging printout ------ */ + +#ifdef DEBUG + +void +debug_print_gb_options(gx_bitmap_format_t options) +{ + static const char *const option_names[] = + { + GX_BITMAP_FORMAT_NAMES + }; + const char *prev = " "; + int i; + + dlprintf1("0x%lx", (ulong) options); + for (i = 0; i < sizeof(options) * 8; ++i) + if ((options >> i) & 1) { + dprintf2("%c%s", + (!memcmp(prev, option_names[i], 3) ? '|' : ','), + option_names[i]); + prev = option_names[i]; + } + dputc('\n'); +} + +void +debug_print_gb_params(gs_get_bits_params_t * params) +{ + gs_get_bits_options_t options = params->options; + + debug_print_gb_options(options); + dprintf1("data[0]=0x%lx", (ulong) params->data[0]); + if (options & GB_OFFSET_SPECIFIED) + dprintf1(" x_offset=%d", params->x_offset); + if (options & GB_RASTER_SPECIFIED) + dprintf1(" raster=%u", params->raster); + dputc('\n'); +} + +#endif /* DEBUG */ diff --git a/pstoraster/gdevhit.c b/pstoraster/gdevhit.c new file mode 100644 index 0000000000..9e16a2a0d7 --- /dev/null +++ b/pstoraster/gdevhit.c @@ -0,0 +1,98 @@ +/* Copyright (C) 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Hit detection device */ +#include "std.h" +#include "gserror.h" +#include "gserrors.h" +#include "gstypes.h" +#include "gsmemory.h" +#include "gxdevice.h" + +/* Define the value returned for a detected hit. */ +const int gs_hit_detected = gs_error_hit_detected; + +/* + * Define a minimal device for insideness testing. + * It returns e_hit whenever it is asked to actually paint any pixels. + */ +private dev_proc_fill_rectangle(hit_fill_rectangle); +const gx_device gs_hit_device = +{std_device_std_body(gx_device, 0, "hit detector", + 0, 0, 1, 1), + {NULL, /* open_device */ + NULL, /* get_initial_matrix */ + NULL, /* sync_output */ + NULL, /* output_page */ + NULL, /* close_device */ + gx_default_map_rgb_color, + gx_default_map_color_rgb, + hit_fill_rectangle, + NULL, /* tile_rectangle */ + NULL, /* copy_mono */ + NULL, /* copy_color */ + gx_default_draw_line, + NULL, /* get_bits */ + NULL, /* get_params */ + NULL, /* put_params */ + gx_default_map_cmyk_color, + NULL, /* get_xfont_procs */ + NULL, /* get_xfont_device */ + gx_default_map_rgb_alpha_color, + gx_default_get_page_device, + gx_default_get_alpha_bits, + NULL, /* copy_alpha */ + gx_default_get_band, + NULL, /* copy_rop */ + gx_default_fill_path, + NULL, /* stroke_path */ + NULL, /* 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, + gx_default_strip_tile_rectangle, + gx_default_strip_copy_rop, + gx_get_largest_clipping_box, + gx_default_begin_typed_image, + NULL, /* get_bits_rectangle */ + gx_default_map_color_rgb_alpha, + gx_non_imaging_create_compositor, + NULL /* get_hardware_params */ + } +}; + +/* Test for a hit when filling a rectangle. */ +private int +hit_fill_rectangle(gx_device * dev, int x, int y, int w, int h, + gx_color_index color) +{ + if (w > 0 && h > 0) + return_error(gs_error_hit_detected); + return 0; +} diff --git a/pstoraster/gdevht.h b/pstoraster/gdevht.h new file mode 100644 index 0000000000..a2f665f12a --- /dev/null +++ b/pstoraster/gdevht.h @@ -0,0 +1,51 @@ +/* Copyright (C) 1995, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Requires gxdevice.h */ + +#ifndef gdevht_INCLUDED +# define gdevht_INCLUDED + +#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). + * We represent colors by packing the two colors being halftoned and the + * halftone level into a gx_color_index. + */ +typedef struct gx_device_ht_s { + gx_device_forward_common; + /* Following + target 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. */ + int color_shift; /* # of bits of color */ + int level_shift; /* = color_shift * 2 */ + gx_color_index color_mask; /* (1 << color_shift) - 1 */ + gs_int_point phase; /* halftone tile offset */ +} gx_device_ht; + +#endif /* gdevht_INCLUDED */ diff --git a/pstoraster/gdevm1.c b/pstoraster/gdevm1.c new file mode 100644 index 0000000000..d474967110 --- /dev/null +++ b/pstoraster/gdevm1.c @@ -0,0 +1,759 @@ +/* Copyright (C) 1989, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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 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, + gx_default_map_cmyk_color, gx_no_copy_alpha, + mem_mono_strip_tile_rectangle, mem_mono_strip_copy_rop, + mem_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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]) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + +#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. + * + * Since source and destination are both always big-endian, + * fetching an aligned chunk never requires byte swapping. + */ +#define CFETCH_ALIGNED(cptr)\ + (*(const chunk *)(cptr)) + +/* + * 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 + +typedef enum { + COPY_OR = 0, COPY_STORE, COPY_AND, COPY_FUNNY +} copy_function; +typedef struct { + uint invert; + copy_function op; +} copy_mode; + +/* + * Map from to copy_mode. + * Logically, this is a 2-D array. + * The indexing is (transparent, 0, 1, unused). */ +private const copy_mode copy_modes[16] = +{ + {~0, COPY_FUNNY}, /* NN */ + {~0, COPY_AND}, /* N0 */ + {0, COPY_OR}, /* N1 */ + {0, 0}, /* unused */ + {0, COPY_AND}, /* 0N */ + {0, COPY_FUNNY}, /* 00 */ + {0, COPY_STORE}, /* 01 */ + {0, 0}, /* unused */ + {~0, COPY_OR}, /* 1N */ + {~0, COPY_STORE}, /* 10 */ + {0, COPY_FUNNY}, /* 11 */ + {0, 0}, /* unused */ + {0, 0}, /* unused */ + {0, 0}, /* unused */ + {0, 0}, /* unused */ + {0, 0}, /* unused */ +}; + +/* Handle the funny cases that aren't supposed to happen. */ +#define FUNNY_CASE()\ + (invert ? gs_note_error(-1) :\ + mem_mono_fill_rectangle(dev, x, y, w, h, color0)) + +private int +mem_mono_copy_mono(gx_device * dev, + const byte * source_data, int source_x, int source_raster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index color0, gx_color_index color1) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + +#ifdef USE_COPY_ROP + return mem_mono_copy_rop(dev, source_data, source_x, source_raster, + id, NULL, NULL, NULL, + x, y, w, h, 0, 0, + ((color0 == gx_no_color_index ? rop3_D : + color0 == 0 ? rop3_0 : rop3_1) & ~rop3_S) | + ((color1 == gx_no_color_index ? rop3_D : + color1 == 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; + + DECLARE_SCAN_PTR_VARS(dbptr, byte *, dest_raster); +#define optr ((chunk *)dbptr) + register int skew; + register uint invert; + + fit_copy(dev, source_data, source_x, source_raster, id, x, y, w, h); +#if gx_no_color_index_value != -1 /* hokey! */ + if (color0 == gx_no_color_index) + color0 = -1; + if (color1 == gx_no_color_index) + color1 = -1; +#endif + mode = copy_modes[((int)color0 << 2) + (int)color1 + 5]; + invert = mode.invert; /* load register */ + SETUP_RECT_VARS(dbptr, byte *, dest_raster); + bptr = source_data + ((source_x & ~chunk_align_bit_mask) >> 3); + dbit = x & chunk_align_bit_mask; + skew = dbit - (source_x & 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)\ + 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);\ + if ( --h == 0 ) break;\ + END_Y_LOOP(source_raster, dest_raster);\ + } + +#define WRITE1_LOOP(src)\ + switch ( mode.op ) {\ + 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: return FUNNY_CASE();\ + } + + 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);\ + if ( --h == 0 ) break;\ + END_Y_LOOP(source_raster, dest_raster);\ + } +#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);\ + if ( --h == 0 ) break;\ + END_Y_LOOP(source_raster, dest_raster);\ + } +#endif + + switch (mode.op) { + 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: + return FUNNY_CASE(); + } +#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 = source_raster - words; + uint dskip = dest_raster - 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); }\ + if ( --h == 0 ) break;\ + END_Y_LOOP(sskip, dskip);\ + } + + switch (mode.op) { + 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: + return FUNNY_CASE(); + } +#undef WRITE_ALIGNED + } else { /* not aligned */ + int cskew = -skew & chunk_bit_mask; + bool case_right = + (skew >= 0 ? true : + ((bptr += chunk_bytes), false)); + + skew &= chunk_bit_mask; + +#define WRITE_UNALIGNED(wr_op, wr_op_masked)\ + /* Prefetch partial word. */\ + bits =\ + (case_right ? CFETCH_RIGHT(bptr, skew, cskew) :\ + CFETCH2(bptr - chunk_bytes, cskew, skew));\ + 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 (mode.op) { + case COPY_OR: + for (;;) { + int count = wleft; + + WRITE_UNALIGNED(WRITE_OR, WRITE_OR_MASKED); + if (--h == 0) + break; + END_Y_LOOP(sskip, dskip); + } + break; + case COPY_STORE: + for (;;) { + int count = wleft; + + WRITE_UNALIGNED(WRITE_STORE, WRITE_STORE_MASKED); + if (--h == 0) + break; + END_Y_LOOP(sskip, dskip); + } + break; + case COPY_AND: + for (;;) { + int count = wleft; + + WRITE_UNALIGNED(WRITE_AND, WRITE_AND_MASKED); + if (--h == 0) + break; + END_Y_LOOP(sskip, dskip); + } + break; + default /*case COPY_FUNNY */ : + return FUNNY_CASE(); + } +#undef WRITE_UNALIGNED + } + } +#undef END_Y_LOOP +#undef NEXT_X_CHUNK + return 0; +#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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + +#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 source_raster; + uint tile_bits_size; + const byte *source_data; + const byte *end; + int x, rw, w, h; + register const byte *bptr; /* actually chunk * */ + int dbit, wleft; + uint mask; + byte *dbase; + + DECLARE_SCAN_PTR_VARS(dbptr, byte *, dest_raster); +#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; + source_raster = tiles->raster; + source_data = tiles->data + ((y + py) % tiles->rep_height) * source_raster; + tile_bits_size = tiles->size.y * source_raster; + end = tiles->data + tile_bits_size; +#undef END_Y_LOOP +#define END_Y_LOOP(sdelta, ddelta)\ + if ( end - bptr <= sdelta ) /* wrap around */\ + bptr -= tile_bits_size;\ + bptr += sdelta; dbptr += ddelta + dest_raster = 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 source_x = 0. + */ + { + int source_x = (x + px) % tiles->rep_width; + + w = tiles->size.x - source_x; + bptr = source_data + ((source_x & ~chunk_align_bit_mask) >> 3); + dbit = x & chunk_align_bit_mask; + skew = dbit - (source_x & 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);\ + if ( --h == 0 ) break;\ + END_Y_LOOP(source_raster, dest_raster);\ + } + 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); + if (--h == 0) + break; + END_Y_LOOP(source_raster, dest_raster); + } +#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); + if (--h == 0) + break; + END_Y_LOOP(source_raster, dest_raster); + } +#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 = source_raster - words; + uint dskip = dest_raster - 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); + } + if (--h == 0) + break; + 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); + } + if (--h == 0) + break; + 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 = source_data; + 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 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, + gx_default_map_cmyk_color, gx_no_copy_alpha, + mem1_word_strip_tile_rectangle, gx_no_strip_copy_rop, + mem_word_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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 * source_data, int source_x, int source_raster, gx_bitmap_id id, + int x, int y, int w, int h, gx_color_index color0, gx_color_index color1) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + byte *row; + uint raster; + bool store; + + fit_copy(dev, source_data, source_x, source_raster, id, x, y, w, h); + row = scan_line_base(mdev, y); + raster = mdev->raster; + store = (color0 != gx_no_color_index && color1 != gx_no_color_index); + mem_swap_byte_rect(row, raster, x, w, h, store); + mem_mono_copy_mono(dev, source_data, source_x, source_raster, id, + x, y, w, h, color0, color1); + 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..9a9413a94f --- /dev/null +++ b/pstoraster/gdevm16.c @@ -0,0 +1,168 @@ +/* Copyright (C) 1994, 1996, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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 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_default_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 >> 5) & 0x3f; + prgb[1] = ((value << 10) + (value << 4) + (value >> 2)) + >> (16 - gx_color_value_bits); + value = color & 0x1f; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; +#if arch_is_big_endian + const ushort color16 = (ushort)color; +#else + const ushort color16 = (ushort)((color << 8) | (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; +} + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; +#if arch_is_big_endian + const ushort zero16 = (ushort)zero; + const ushort 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; +} + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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..12cf8ec9b8 --- /dev/null +++ b/pstoraster/gdevm2.c @@ -0,0 +1,259 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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 */ + +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 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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 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, + gx_default_map_cmyk_color, gx_default_strip_tile_rectangle, + gx_no_strip_copy_rop, mem_word_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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..1e3a4b9328 --- /dev/null +++ b/pstoraster/gdevm24.c @@ -0,0 +1,526 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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 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, + gx_default_map_cmyk_color, mem_true24_copy_alpha, + gx_default_strip_tile_rectangle, mem_true24_strip_copy_rop, + mem_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + declare_unpack_color(r, g, b, color); + declare_scan_ptr(dest); + + /* + * In order to avoid testing w > 0 and h > 0 twice, we defer + * executing setup_rect, and use fit_fill_xywh instead of + * fit_fill. + */ + fit_fill_xywh(dev, x, y, w, h); + if (w >= 5) { + if (h <= 0) + return 0; + setup_rect(dest); + 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 */ + setup_rect(dest); + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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 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, + gx_default_map_cmyk_color, gx_default_strip_tile_rectangle, + gx_no_strip_copy_rop, mem_word_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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..d354833236 --- /dev/null +++ b/pstoraster/gdevm32.c @@ -0,0 +1,249 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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 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, + gx_default_cmyk_map_cmyk_color, gx_default_strip_tile_rectangle, + gx_default_strip_copy_rop, mem_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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 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, + gx_default_cmyk_map_cmyk_color, gx_default_strip_tile_rectangle, + gx_no_strip_copy_rop, mem_word_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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..e0df0e13f6 --- /dev/null +++ b/pstoraster/gdevm4.c @@ -0,0 +1,319 @@ +/* Copyright (C) 1992, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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 */ + +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 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + const byte *line; + declare_scan_ptr(dest); + byte invert, bb; + + fit_copy(dev, base, sourcex, sraster, id, x, y, w, h); + setup_rect(dest); + line = base + (sourcex >> 3); + /* Divide into opaque and masked cases. */ + if (one == gx_no_color_index) { + if (zero == gx_no_color_index) + return 0; /* nothing to do */ + invert = 0xff; + bb = ((byte) zero << 4) | (byte) zero; + } else if (zero == gx_no_color_index) { + invert = 0; + bb = ((byte) one << 4) | (byte) one; + } else { + /* Opaque case. */ + int shift = ~(sourcex ^ x) & 1; + byte oz[4]; + + oz[0] = (byte)((zero << 4) | zero); + oz[1] = (byte)((zero << 4) | one); + oz[2] = (byte)((one << 4) | zero); + oz[3] = (byte)((one << 4) | one); + do { + register byte *dptr = (byte *) dest; + const byte *sptr = line; + register uint sbyte = *sptr++; + register int sbit = ~sourcex & 7; + int count = w; + + /* + * If the first source bit corresponds to an odd X in the + * destination, process it now. + */ + if (x & 1) { + *dptr = (*dptr & 0xf0) | + ((sbyte >> sbit) & 1 ? one : zero); + --count; /* may now be 0 */ + if (--sbit < 0) + sbit = 7, sbyte = *sptr++; + ++dptr; + } + /* + * Now we know the next destination X is even. We want to + * process 2 source bits at a time from now on, so set things up + * properly depending on whether the next source X (bit) is even + * or odd. In both even and odd cases, the active source bits + * are in bits 8..1 of sbyte. + */ + sbyte <<= shift; + sbit += shift - 1; + /* + * Now bit # sbit+1 is the most significant unprocessed bit + * in sbyte. -1 <= sbit <= 7; sbit is odd. + * Note that if sbit = -1, all of sbyte has been processed. + * + * Continue processing pairs of bits in the first source byte. + */ + while (count >= 2 && sbit >= 0) { + *dptr++ = oz[(sbyte >> sbit) & 3]; + sbit -= 2, count -= 2; + } + /* + * Now sbit = -1 iff we have processed the entire first source + * byte. + * + * Process full source bytes. + */ + if (shift) { + sbyte >>= 1; /* in case count < 8 */ + for (; count >= 8; dptr += 4, count -= 8) { + sbyte = *sptr++; + dptr[0] = oz[sbyte >> 6]; + dptr[1] = oz[(sbyte >> 4) & 3]; + dptr[2] = oz[(sbyte >> 2) & 3]; + dptr[3] = oz[sbyte & 3]; + } + sbyte <<= 1; + } else { + for (; count >= 8; dptr += 4, count -= 8) { + sbyte = (sbyte << 8) | *sptr++; + dptr[0] = oz[(sbyte >> 7) & 3]; + dptr[1] = oz[(sbyte >> 5) & 3]; + dptr[2] = oz[(sbyte >> 3) & 3]; + dptr[3] = oz[(sbyte >> 1) & 3]; + } + } + if (!count) + continue; + /* + * Process pairs of bits in the final source byte. Note that + * if sbit > 0, this is still the first source byte (the + * full-byte loop wasn't executed). + */ + if (sbit < 0) { + sbyte = (sbyte << 8) | (*sptr << shift); + sbit = 7; + } + while (count >= 2) { + *dptr++ = oz[(sbyte >> sbit) & 3]; + sbit -= 2, count -= 2; + } + /* + * If the final source bit corresponds to an even X value, + * process it now. + */ + if (count) { + *dptr = (*dptr & 0x0f) | + (((sbyte >> sbit) & 2 ? one : zero) << 4); + } + } while ((line += sraster, inc_ptr(dest, draster), --h) > 0); + return 0; + } + /* Masked case. */ + do { + register byte *dptr = (byte *) dest; + const byte *sptr = line; + register int sbyte = *sptr++ ^ invert; + register int sbit = 0x80 >> (sourcex & 7); + register byte mask = (x & 1 ? 0x0f : 0xf0); + int count = w; + + do { + if (sbyte & sbit) + *dptr = (*dptr & ~mask) | (bb & mask); + if ((sbit >>= 1) == 0) + sbit = 0x80, sbyte = *sptr++ ^ invert; + dptr += (mask = ~mask) >> 7; + } while (--count > 0); + line += sraster; + inc_ptr(dest, draster); + } while (--h > 0); + 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) +{ + /* Use monobit copy_mono. */ + int code; + + /* 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 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, + gx_default_map_cmyk_color, gx_default_strip_tile_rectangle, + gx_no_strip_copy_rop, mem_word_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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..875bcaddb8 --- /dev/null +++ b/pstoraster/gdevm8.c @@ -0,0 +1,247 @@ +/* Copyright (C) 1994, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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 */ +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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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 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, + gx_default_map_cmyk_color, gx_default_strip_tile_rectangle, + gx_no_strip_copy_rop, mem_word_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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..231e41920d --- /dev/null +++ b/pstoraster/gdevmem.c @@ -0,0 +1,498 @@ +/* Copyright (C) 1989, 1995, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Generic "memory" (stored bitmap) device */ +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsrect.h" +#include "gsstruct.h" +#include "gxarith.h" +#include "gxdevice.h" +#include "gxgetbit.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 ENUM_USING(st_device_forward, vptr, sizeof(gx_device_forward), index - 2); +} +case 0: +ENUM_RETURN((mptr->foreign_bits ? NULL : (void *)mptr->base)); +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); + RELOC_USING(st_device_forward, vptr, sizeof(gx_device_forward)); +} +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) +{ + gx_device_init((gx_device *) dev, (const gx_device *)mdproto, + mem, true); + dev->stype = &st_device_memory; + switch (page_device) { + case -1: + set_dev_proc(dev, get_page_device, gx_default_get_page_device); + break; + case 1: + set_dev_proc(dev, 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + *dev = mem_mono_device; + dev->memory = mem; + set_dev_proc(dev, get_page_device, gx_default_get_page_device); + mdev->target = target; + gdev_mem_mono_set_inverted(dev, true); + rc_init(dev, mem, 0); +} + + +/* 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, int width, int height) +{ + return round_up((ulong) height * + bitmap_raster(width * dev->color_info.depth), + max(align_bitmap_mod, arch_align_ptr_mod)); +} +ulong +gdev_mem_data_size(const gx_device_memory * dev, int width, int height) +{ + return mem_bitmap_bits_size(dev, width, height) + + (ulong) height *sizeof(byte *); + +} +/* + * Do the inverse computation: given a width (in pixels) and a buffer size, + * compute the maximum height. + */ +int +gdev_mem_max_height(const gx_device_memory * dev, int width, ulong size) +{ + ulong max_height = size / + (bitmap_raster(width * dev->color_info.depth) + sizeof(byte *)); + int height = (int)min(max_height, max_int); + + /* + * Because of alignment rounding, the just-computed height might + * be too large by a small amount. Adjust it the easy way. + */ + while (gdev_mem_data_size(dev, width, height) > size) + --height; + return height; +} + +/* Open a memory device, allocating the data area if appropriate, */ +/* and create the scan line table. */ +private void mem_set_line_ptrs(P4(gx_device_memory *, byte **, byte *, int)); +int +mem_open(gx_device * dev) +{ + return gdev_mem_open_scan_lines((gx_device_memory *)dev, dev->height); +} +int +gdev_mem_open_scan_lines(gx_device_memory *mdev, int setup_height) +{ + if (setup_height < 0 || setup_height > mdev->height) + return_error(gs_error_rangecheck); + 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->width, + mdev->height)), + mdev->base, setup_height); + return 0; +} +/* Set up the scan line pointers of a memory device. */ +/* Sets line_ptrs, base, raster; uses width, color_info.depth. */ +private void +mem_set_line_ptrs(gx_device_memory * mdev, byte ** line_ptrs, byte * base, + int count /* >= 0 */) +{ + byte **pptr = mdev->line_ptrs = line_ptrs; + byte **pend = pptr + count; + byte *scan_line = mdev->base = base; + uint raster = mdev->raster = gdev_mem_raster(mdev); + + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + + if (mdev->bitmap_memory != 0) + gs_free_object(mdev->bitmap_memory, mdev->base, "mem_close"); + return 0; +} + +/* Copy bits to a client. */ +#undef chunk +#define chunk byte +int +mem_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, + gs_get_bits_params_t * params, gs_int_rect ** unread) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + gs_get_bits_options_t options = params->options; + int x = prect->p.x, w = prect->q.x - x, y = prect->p.y, h = prect->q.y - y; + + if (options == 0) { + params->options = + (GB_ALIGN_STANDARD | GB_ALIGN_ANY) | + (GB_RETURN_COPY | GB_RETURN_POINTER) | + (GB_OFFSET_0 | GB_OFFSET_SPECIFIED | GB_OFFSET_ANY) | + (GB_RASTER_STANDARD | GB_RASTER_SPECIFIED | GB_RASTER_ANY) | + GB_PACKING_CHUNKY | GB_COLORS_NATIVE | GB_ALPHA_NONE; + return_error(gs_error_rangecheck); + } + if ((w <= 0) | (h <= 0)) { + if ((w | h) < 0) + return_error(gs_error_rangecheck); + return 0; + } + if (x < 0 || w > dev->width - x || + y < 0 || h > dev->height - y + ) + return_error(gs_error_rangecheck); + { + byte *base = scan_line_base(mdev, y); + int code = gx_get_bits_return_pointer(dev, x, h, params, + GB_COLORS_NATIVE | GB_PACKING_CHUNKY | + GB_ALPHA_NONE, base); + + if (code >= 0) + return code; + return gx_get_bits_copy(dev, x, w, h, params, + GB_COLORS_NATIVE | GB_PACKING_CHUNKY | + GB_ALPHA_NONE, base, + gx_device_raster(dev, true)); + } +} + +#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. + * Note that the coordinates are specified in bits, not in terms of the + * actual device depth. + */ +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 rectangle to the client, swapping bytes as needed. */ +int +mem_word_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, + gs_get_bits_params_t * params, gs_int_rect ** unread) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + byte *src; + uint dev_raster = gx_device_raster(dev, 1); + int x = prect->p.x; + int w = prect->q.x - x; + int y = prect->p.y; + int h = prect->q.y - y; + int bit_x, bit_w; + int code; + + fit_fill_xywh(dev, x, y, w, h); + if (w <= 0 || h <= 0) { + /* + * It's easiest to just keep going with an empty rectangle. + * We pass the original rectangle to mem_get_bits_rectangle, + * so unread will be filled in correctly. + */ + x = y = w = h = 0; + } + bit_x = x * dev->color_info.depth; + bit_w = w * dev->color_info.depth; + src = scan_line_base(mdev, y); + mem_swap_byte_rect(src, dev_raster, bit_x, bit_w, h, false); + code = mem_get_bits_rectangle(dev, prect, params, unread); + mem_swap_byte_rect(src, dev_raster, bit_x, bit_w, h, false); + return code; +} + +#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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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]) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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..17dc5c059e --- /dev/null +++ b/pstoraster/gdevmem.h @@ -0,0 +1,233 @@ +/* Copyright (C) 1991, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Private definitions for memory devices. */ + +#ifndef gdevmem_INCLUDED +# define gdevmem_INCLUDED + +#include "gxbitops.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_VARS(ptr, chunk *, draster) +#define DECLARE_SCAN_PTR_VARS(ptr, ptype, draster)\ + register ptype ptr;\ + uint draster +#define setup_rect(ptr)\ + SETUP_RECT_VARS(ptr, chunk *, draster) +#define SETUP_RECT_VARS(ptr, ptype, draster)\ + 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_rectangle(mem_get_bits_rectangle); +/* The following are for word-oriented devices. */ +#if arch_is_big_endian +# define mem_word_get_bits_rectangle mem_get_bits_rectangle +#else +dev_proc_get_bits_rectangle(mem_word_get_bits_rectangle); +#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, map_cmyk_color, copy_alpha, strip_tile_rectangle, strip_copy_rop, get_bits_rectangle)\ +{ 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,\ + gx_default_get_bits,\ + 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 */\ + gx_default_get_clipping_box,\ + gx_default_begin_typed_image,\ + get_bits_rectangle, /* differs */\ + gx_default_map_color_rgb_alpha,\ + gx_default_create_compositor,\ + gx_default_get_hardware_params,\ + gx_default_text_begin\ + },\ + 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, map_cmyk_color, strip_tile_rectangle, strip_copy_rop, get_bits_rectangle)\ + mem_full_alpha_device(name, rgb_depth, gray_depth, open, map_rgb_color,\ + map_color_rgb, copy_mono, copy_color, fill_rectangle,\ + map_cmyk_color, gx_default_copy_alpha,\ + strip_tile_rectangle, strip_copy_rop,\ + get_bits_rectangle) +#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,\ + gx_default_map_cmyk_color, gx_default_strip_tile_rectangle,\ + strip_copy_rop, mem_get_bits_rectangle) + +/* 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) + +/* ------ Implementations ------ */ + +extern const gx_device_memory mem_mono_device; +extern const gx_device_memory mem_mapped2_device; +extern const gx_device_memory mem_mapped4_device; +extern const gx_device_memory mem_mapped8_device; +extern const gx_device_memory mem_true16_device; +extern const gx_device_memory mem_true24_device; +extern const gx_device_memory mem_true32_device; +extern const gx_device_memory 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 mem_mono_word_device; +extern const gx_device_memory mem_mapped2_word_device; +extern const gx_device_memory mem_mapped4_word_device; +extern const gx_device_memory mem_mapped8_word_device; +extern const gx_device_memory mem_true24_word_device; +extern const gx_device_memory 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 */ + +#endif /* gdevmem_INCLUDED */ diff --git a/pstoraster/gdevmgr.h b/pstoraster/gdevmgr.h new file mode 100644 index 0000000000..0cab14414d --- /dev/null +++ b/pstoraster/gdevmgr.h @@ -0,0 +1,127 @@ +/* Copyright (C) 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$*/ +/* Common header file for MGR devices */ + +#ifndef gdevmgr_INCLUDED +# define gdevmgr_INCLUDED + +#define MGR_RESERVEDCOLORS 16 + +/* Color mapping routines for 8-bit color (with a fixed palette). */ +dev_proc_map_rgb_color(mgr_8bit_map_rgb_color); +dev_proc_map_color_rgb(mgr_8bit_map_color_rgb); + + +/* extract from dump.h */ + +/* + * format for saved bitmaps + */ + +#define B_PUTHDR8(hdr, w, h, d) ( \ + (hdr)->magic[0] = 'y', (hdr)->magic[1] = 'z', \ + (hdr)->h_wide = (((w) >> 6) & 0x3f) + ' ', \ + (hdr)->l_wide = ((w) & 0x3f) + ' ', \ + (hdr)->h_high = (((h) >> 6) & 0x3f) + ' ', \ + (hdr)->l_high = ((h) & 0x3f) + ' ', \ + (hdr)->depth = ((d) & 0x3f) + ' ', \ + (hdr)->_reserved = ' ' ) + +struct b_header { + char magic[2]; /* magics */ + char h_wide; /* upper byte width (biased with 0x20) */ + char l_wide; /* lower byte width (biased with 0x20) */ + char h_high; /* upper byte height (biased with 0x20) */ + char l_high; /* lower byte height (biased with 0x20) */ + char depth; /* depth (biased with 0x20) */ + char _reserved; /* for alignment */ +}; + +/* + * Color lookup table information + */ +struct nclut { + unsigned short colnum; + unsigned short red, green, blue; +} ; + + +/* extract from color.h */ + +/* + * MGR Color Definitions + */ + +#define LUT_BW 0 +#define LUT_GREY 1 +#define LUT_BGREY 2 +#define LUT_VGA 3 +#define LUT_BCT 4 +#define LUT_USER 5 +#define LUT 6 +#define LUT_8 LUT + +#define RGB_RED 0 +#define RGB_GREEN 1 +#define RGB_BLUE 2 +#define RGB 3 + +#define LUTENTRIES 16 + +#define BW_RED 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0 +#define BW_GREEN BW_RED +#define BW_BLUE BW_RED + +#define GREY_RED 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +#define GREY_GREEN GREY_RED +#define GREY_BLUE GREY_RED + +#define BGREY_RED 1, 0, 2, 8, 4, 3, 13, 11, 7, 6, 10, 12, 14, 5, 9, 15 +#define BGREY_GREEN BGREY_RED +#define BGREY_BLUE BGREY_RED + +#define VGA_RED 0, 0, 0, 0, 8, 8, 8, 12, 8, 0, 0, 0, 15, 15, 15, 15 +#define VGA_GREEN 0, 0, 8, 8, 0, 0, 8, 12, 8, 0, 15, 15, 0, 0, 15, 15 +#define VGA_BLUE 0, 8, 0, 8, 0, 8, 0, 12, 8, 15, 0, 15, 0, 15, 0, 15 + +#define BCT_RED 1, 7, 6, 15, 14, 3, 13, 11, 7, 13, 13, 15, 15, 5, 9, 15 +#define BCT_GREEN 1, 7, 13, 12, 5, 3, 13, 11, 7, 14, 15, 15, 14, 5, 9, 15 +#define BCT_BLUE 1, 14, 6, 8, 5, 3, 13, 11, 7, 15, 14, 12, 13, 5, 9, 15 + +#define USER_RED 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +#define USER_GREEN USER_RED +#define USER_BLUE USER_RED + +static char mgrlut[LUT][RGB][LUTENTRIES] = { + { { BW_RED }, { BW_GREEN }, { BW_BLUE } }, + { { GREY_RED }, { GREY_GREEN }, { GREY_BLUE } }, + { { BGREY_RED }, { BGREY_GREEN }, { BGREY_BLUE } }, + { { VGA_RED }, { VGA_GREEN }, { VGA_BLUE } }, + { { BCT_RED }, { BCT_GREEN }, { BCT_BLUE } }, + { { USER_RED }, { USER_GREEN }, { USER_BLUE } } +}; + +#endif /* gdevmgr_INCLUDED */ diff --git a/pstoraster/gdevmpla.c b/pstoraster/gdevmpla.c new file mode 100644 index 0000000000..239ffbcc8a --- /dev/null +++ b/pstoraster/gdevmpla.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1993, 1994, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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_rectangle(mem_planar_get_bits_rectangle); +const gx_device_memory 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, + gx_default_map_cmyk_color, gx_default_strip_tile_rectangle, + gx_no_strip_copy_rop, mem_planar_get_bits_rectangle); + +/* 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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) +{ + gx_device_memory * const mdev = (gx_device_memory *)dev; + 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_rectangle(gx_device * dev, const gs_int_rect * prect, + gs_get_bits_params_t * params, gs_int_rect ** unread) +{ + return_error(-1); +} diff --git a/pstoraster/gdevmrop.h b/pstoraster/gdevmrop.h new file mode 100644 index 0000000000..3c143c9212 --- /dev/null +++ b/pstoraster/gdevmrop.h @@ -0,0 +1,97 @@ +/* Copyright (C) 1995, 1996, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Definitions for device RasterOp implementations. */ +/* Requires gxdevmem.h, gsropt.h */ + +#ifndef gdevmrop_INCLUDED +# define gdevmrop_INCLUDED + +/* Define the table of RasterOp implementation procedures. */ +extern const rop_proc rop_proc_table[256]; + +/* Define the table of RasterOp operand usage. */ +extern const byte /*rop_usage_t */ rop_usage_table[256]; + +/* + * Compute the effective RasterOp for the 1-bit case, + * taking transparency into account. + */ +gs_rop3_t gs_transparent_rop(P1(gs_logical_operation_t lop)); + +#ifdef DEBUG +/* Trace a [strip_]copy_rop call. */ +void trace_copy_rop(P16(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)); +#endif + +/* + * 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 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; + gx_device_color texture; +}; + +#define private_st_device_rop_texture() /* in gdevrops.c */\ + gs_private_st_composite(st_device_rop_texture, gx_device_rop_texture,\ + "gx_device_rop_texture", device_rop_texture_enum_ptrs, device_rop_texture_reloc_ptrs) + +/* Create a RasterOp source device. */ +int gx_alloc_rop_texture_device(P3(gx_device_rop_texture ** prsdev, + gs_memory_t * mem, + client_name_t cname)); + +/* 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)); + +#endif /* gdevmrop_INCLUDED */ diff --git a/pstoraster/gdevnfwd.c b/pstoraster/gdevnfwd.c new file mode 100644 index 0000000000..e8cbb0fd92 --- /dev/null +++ b/pstoraster/gdevnfwd.c @@ -0,0 +1,797 @@ +/* Copyright (C) 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Null and forwarding device implementation */ +#include "gx.h" +#include "gserrors.h" +#include "gxdevice.h" + +/* ---------------- Forwarding procedures ---------------- */ + +/* 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); + 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); + /* NOT image_data (OBSOLETE) */ + /* NOT end_image (OBSOLETE) */ + /* NOT strip_tile_rectangle */ + fill_dev_proc(dev, strip_copy_rop, gx_forward_strip_copy_rop); + fill_dev_proc(dev, get_clipping_box, gx_forward_get_clipping_box); + fill_dev_proc(dev, begin_typed_image, gx_forward_begin_typed_image); + fill_dev_proc(dev, get_bits_rectangle, gx_forward_get_bits_rectangle); + fill_dev_proc(dev, map_color_rgb_alpha, gx_forward_map_color_rgb_alpha); + fill_dev_proc(dev, create_compositor, gx_no_create_compositor); + fill_dev_proc(dev, get_hardware_params, gx_forward_get_hardware_params); + fill_dev_proc(dev, text_begin, gx_forward_text_begin); + 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); + set_dev_proc(dev, map_color_rgb_alpha, gx_forward_map_color_rgb_alpha); +} + +void +gx_forward_get_initial_matrix(gx_device * dev, gs_matrix * pmat) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_fill_rectangle(gx_device * dev, int x, int y, int w, int h, + gx_color_index color) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + if (tdev == 0) + return_error(gs_error_Fatal); + return (*dev_proc(tdev, fill_rectangle)) (tdev, x, y, w, h, color); +} + +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_forward * const fdev = (gx_device_forward *)dev; + 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_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) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + if (tdev == 0) + return_error(gs_error_Fatal); + return (*dev_proc(tdev, copy_mono)) + (tdev, data, dx, raster, id, x, y, w, h, zero, one); +} + +int +gx_forward_copy_color(gx_device * dev, const byte * data, + int dx, int raster, gx_bitmap_id id, int x, int y, int w, int h) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + if (tdev == 0) + return_error(gs_error_Fatal); + return (*dev_proc(tdev, copy_color)) + (tdev, data, dx, raster, id, x, y, w, h); +} + +int +gx_forward_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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)); +} + +const gx_xfont_procs * +gx_forward_get_xfont_procs(gx_device * dev) +{ + gx_device_forward * const fdev = (gx_device_forward *)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_forward * const fdev = (gx_device_forward *)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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + gx_device *pdev; + + if (tdev == 0) + return gx_default_get_page_device(dev); + pdev = (*dev_proc(tdev, get_page_device)) (tdev); + return (pdev == tdev ? dev : pdev); +} + +int +gx_forward_get_alpha_bits(gx_device * dev, graphics_object_type type) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_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_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->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_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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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) (tdev, 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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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_forward * const fdev = (gx_device_forward *)dev; + 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, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * memory, gx_image_enum_common_t ** pinfo) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + 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, prect, pdcolor, pcpath, + memory, pinfo); +} + +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_forward * const fdev = (gx_device_forward *)dev; + 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); +} + +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_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->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); +} + +void +gx_forward_get_clipping_box(gx_device * dev, gs_fixed_rect * pbox) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + if (tdev == 0) + gx_default_get_clipping_box(dev, pbox); + else + (*dev_proc(tdev, get_clipping_box)) (tdev, pbox); +} + +int +gx_forward_begin_typed_image(gx_device * dev, + const gs_imager_state * pis, const gs_matrix * pmat, + const gs_image_common_t * pim, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * memory, gx_image_enum_common_t ** pinfo) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + dev_proc_begin_typed_image((*proc)); + + if (tdev == 0) + tdev = dev, proc = gx_default_begin_typed_image; + else + proc = dev_proc(tdev, begin_typed_image); + return (*proc) (tdev, pis, pmat, pim, prect, pdcolor, pcpath, + memory, pinfo); +} + +int +gx_forward_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, + gs_get_bits_params_t * params, gs_int_rect ** unread) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + dev_proc_get_bits_rectangle((*proc)); + + if (tdev == 0) + tdev = dev, proc = gx_default_get_bits_rectangle; + else + proc = dev_proc(tdev, get_bits_rectangle); + return (*proc) (tdev, prect, params, unread); +} + +int +gx_forward_map_color_rgb_alpha(gx_device * dev, gx_color_index color, + gx_color_value prgba[4]) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + return (tdev == 0 ? gx_default_map_color_rgb_alpha(dev, color, prgba) : + (*dev_proc(tdev, map_color_rgb_alpha)) (tdev, color, prgba)); +} + +int +gx_forward_get_hardware_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + return (tdev == 0 ? gx_default_get_hardware_params(dev, plist) : + (*dev_proc(tdev, get_hardware_params)) (tdev, plist)); +} + +int +gx_forward_text_begin(gx_device * dev, gs_imager_state * pis, + const gs_text_params_t * text, const gs_font * font, +gx_path * path, const gx_device_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * memory, gs_text_enum_t ** ppenum) +{ + gx_device_forward * const fdev = (gx_device_forward *)dev; + gx_device *tdev = fdev->target; + + dev_proc_text_begin((*proc)); + + if (tdev == 0) + tdev = dev, proc = gx_default_text_begin; + else + proc = dev_proc(tdev, text_begin); + return (*proc) (tdev, pis, text, font, path, pdcolor, pcpath, + memory, ppenum); +} + +/* ---------------- 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); + +/* We would like to have null implementations of begin/data/end image, */ +/* but we can't do this, because image_data must keep track of the */ +/* Y position so it can return 1 when done. */ +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,\ + gx_default_begin_image,\ + gx_default_image_data,\ + gx_default_end_image,\ + gx_default_strip_tile_rectangle,\ + null_strip_copy_rop,\ + gx_default_get_clipping_box,\ + gx_default_begin_typed_image,\ + gx_default_get_bits_rectangle,\ + gx_forward_map_color_rgb_alpha,\ + gx_non_imaging_create_compositor,\ + gx_forward_get_hardware_params,\ + gx_default_text_begin\ +} + +const gx_device_null gs_null_device = +{ + std_device_std_body_type_open(gx_device_null, 0, "null", &st_device_null, + 0, 0, 72, 72), + null_procs(gx_default_get_page_device /* not a page device */ ), + 0 /* target */ +}; + +const gx_device_null gs_nullpage_device = +{ +std_device_std_body_type_open(gx_device_null, 0, "nullpage", &st_device_null, + 72 /*nominal */ , 72 /*nominal */ , 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) +{ + /* + * If this is not a page device, we must defeat attempts to reset + * the size; otherwise this is equivalent to gx_forward_put_params. + */ + gx_device_forward * const fdev = (gx_device_forward *)dev; + 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 || (*dev_proc(dev, get_page_device)) (dev) == dev) + 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_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; +} diff --git a/pstoraster/gdevpccm.h b/pstoraster/gdevpccm.h new file mode 100644 index 0000000000..1322594d24 --- /dev/null +++ b/pstoraster/gdevpccm.h @@ -0,0 +1,44 @@ +/* Copyright (C) 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Requires gxdevice.h */ + +#ifndef gdevpccm_INCLUDED +# define gdevpccm_INCLUDED + +/* Color mapping routines for EGA/VGA-style color. */ +dev_proc_map_rgb_color(pc_4bit_map_rgb_color); +dev_proc_map_color_rgb(pc_4bit_map_color_rgb); +#define dci_pc_4bit { 3, 4, 3, 2, 4, 3 } + +/* Color mapping routines for 8-bit color (with a fixed palette). */ +dev_proc_map_rgb_color(pc_8bit_map_rgb_color); +dev_proc_map_color_rgb(pc_8bit_map_color_rgb); +#define dci_pc_8bit { 3, 8, 6, 6, 7, 7 } + +/* Write the palette on a file. */ +int pc_write_palette(P3(gx_device *, uint, FILE *)); + +#endif /* gdevpccm_INCLUDED */ diff --git a/pstoraster/gdevpcfb.h b/pstoraster/gdevpcfb.h new file mode 100644 index 0000000000..21bde1bb9a --- /dev/null +++ b/pstoraster/gdevpcfb.h @@ -0,0 +1,209 @@ +/* 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* IBM PC frame buffer definitions */ + +#ifndef gdevpcfb_INCLUDED +# define gdevpcfb_INCLUDED + +#ifdef __MSDOS__ +# include "dos_.h" +typedef union REGS registers; + +#endif + +/* For testing, the 16-color display may be defined as a monochrome, */ +/* 8-color, or 16-color device. */ +#define ega_bits_of_color 2 /* 0, 1, or 2 */ +#define rgb_max ega_bits_of_color + +/* Define the short (integer) version of "transparent" color. */ +/* ****** Depends on gx_no_color_index being all 1's. ***** */ +#define no_color ((int)gx_no_color_index) + +/* Procedures */ + + /* See gxdevice.h for the definitions of the procedures. */ + +dev_proc_open_device(ega_open); +dev_proc_close_device(ega_close); +dev_proc_fill_rectangle(ega_fill_rectangle); +dev_proc_tile_rectangle(ega_tile_rectangle); +dev_proc_copy_mono(ega_copy_mono); +dev_proc_copy_color(ega_copy_color); +dev_proc_get_bits(ega_get_bits); + +/* Structure for saving state of BIOS variables. */ +typedef struct pcfb_bios_state_s { + int display_mode; /* must be first, see pcfb_save_state */ + /* in gdevpcfb.c */ + byte text_page; + uint text_cursor_mode; + uint text_font; + byte text_attribute; + byte border_color; +} pcfb_bios_state; + +/* Procedures used by gdevpcfb.c */ +void pcfb_set_signals(P1(gx_device *)); +void pcfb_get_state(P1(pcfb_bios_state *)); +void pcfb_set_mode(P1(int)); +void pcfb_set_state(P1(const pcfb_bios_state *)); + +/* Types for frame buffer pointers. */ +typedef byte *fb_ptr; +typedef volatile byte *volatile_fb_ptr; + +/* Define the nominal page height in inches. */ +#ifdef A4 +# define PAGE_HEIGHT_INCHES 11.69 +#else +# define PAGE_HEIGHT_INCHES 11.0 +#endif + +/* The device descriptor */ +typedef struct gx_device_ega_s gx_device_ega; +struct gx_device_ega_s { + gx_device_common; + int raster; /* frame buffer bytes per line */ + int fb_seg_mult; /* multiplier for segment part */ + /* of frame buffer pointer */ + int fb_byte_mult; /* multiplier for word part ditto */ +#define mk_fb_ptr(x, y)\ + (fb_dev->fb_byte_mult == 0 ?\ + (fb_ptr)MK_PTR(regen + (y) * (fb_dev->fb_seg_mult), (x) >> 3) :\ + (fb_ptr)MK_PTR(regen + ((y) >> 4) * (fb_dev->fb_seg_mult),\ + (((y) & 15) * fb_dev->fb_byte_mult) + ((x) >> 3))) + int video_mode; +}; + +/* Macro for creating instances */ +/* The initial parameters map an appropriate fraction of */ +/* the screen to a full-page coordinate space. */ +/* This may or may not be what is desired! */ +#define ega_device(dev_name, procs, fb_raster, screen_height, aspect_ratio, video_mode)\ + { std_device_dci_body(gx_device_ega, &procs, dev_name,\ + fb_raster * 8, screen_height,\ + (screen_height * (aspect_ratio)) / PAGE_HEIGHT_INCHES, /* x dpi */\ + screen_height / PAGE_HEIGHT_INCHES, /* y dpi */\ + (rgb_max ? 3 : 1), /* num_components */\ + 4, /* depth */\ + (rgb_max ? rgb_max : 1), /* max_gray */\ + rgb_max,\ + (rgb_max ? rgb_max + 1 : 2), /* dither_grays */\ + (rgb_max ? rgb_max + 1 : 0) /* dither_colors */\ + ),\ + { 0 }, /* std_procs */\ + fb_raster,\ + (fb_raster & 15 ? fb_raster : fb_raster >> 4),\ + (fb_raster & 15 ? fb_raster : 0),\ + video_mode\ + } + +/* Define the device port and register numbers, and the regen map base */ +#define seq_addr 0x3c4 +#define s_map 2 +#define set_s_map(mask) outport2(seq_addr, s_map, mask) +#define graph_addr 0x3ce +#define g_const 0 /* set/reset */ +#define set_g_const(color) outport2(graph_addr, g_const, color) +#define g_const_map 1 /* enable set/reset */ +#define set_g_const_map(map) outport2(graph_addr, g_const_map, map) +#define g_function 3 +# define gf_WRITE 0 +# define gf_AND 8 +# define gf_OR 0x10 +# define gf_XOR 0x18 +#define set_g_function(func) outport2(graph_addr, g_function, func) +#define g_read_plane 4 +#define set_g_read_plane(plane) outport2(graph_addr, g_read_plane, plane) +#define g_mode 5 +# define gm_DATA 0 +# define gm_FILL 2 +#define set_g_mode(mode) outport2(graph_addr, g_mode, mode) +#define g_mask 8 +#define set_g_mask(mask) outport2(graph_addr, g_mask, mask) +#define select_g_mask() outportb(graph_addr, g_mask) +#define out_g_mask(mask) outportb(graph_addr+1, mask) +#define regen 0xa000 + +/* Define access to the frame buffer and the video registers */ +/* according to whether we are on a DOS system or a Unix system. */ + +#if defined(M_UNIX) || defined(M_XENIX) || defined(UNIX) || defined(SYSV) || defined(__linux__) + + /* SCO Unix/Xenix, AT&T SVR4, or Linux. */ + +#undef outportb + +#if defined(__GNUC__) + /* Inline assembly version for gcc */ + /* Under SCO, requires installing the gnu assembler as "as" */ +static inline void +outportb(int port, int data) +{ + __asm__ volatile ("outb %0,%1":: + "a" ((unsigned char)data), + "d" ((unsigned short)port)); +} +static inline void +outport2(int port, int index, int data) +{ + __asm__ volatile ("movb %0,%%ah; movb %1,%%al; outw %%ax,%2":: + "qmi" ((unsigned char)data), + "qmi" ((unsigned char)index), + "d" ((unsigned short)port): + "eax"); +} +#else +void outportb(P2(uint, byte)); +void outport2(P3(uint, byte, byte)); + +#endif + +/* Redefine mk_fb_ptr -- no segmented addressing. */ + +#undef mk_fb_ptr +extern fb_ptr fb_addr; + +#define mk_fb_ptr(x, y) (fb_addr + (y) * (fb_dev->raster) + ((x) >> 3)) + +#else + + /* MS-DOS */ + +/* outportb is defined in dos_.h */ +#define outport2(port, index, data)\ + (outportb(port, index), outportb((port)+1, data)) + +#endif + +/* Fetch and discard a byte. Prevent the compiler from */ +/* optimizing this away. */ +static unsigned char byte_discard_; + +#define byte_discard(expr) byte_discard_ = (expr) + +#endif /* gdevpcfb_INCLUDED */ diff --git a/pstoraster/gdevpcl.h b/pstoraster/gdevpcl.h new file mode 100644 index 0000000000..b6954f159a --- /dev/null +++ b/pstoraster/gdevpcl.h @@ -0,0 +1,52 @@ +/* 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Requires gdevprn.h */ + +#ifndef gdevpcl_INCLUDED +# define gdevpcl_INCLUDED + +/* Define the PCL paper size codes. */ +#define PAPER_SIZE_LETTER 2 +#define PAPER_SIZE_LEGAL 3 +#define PAPER_SIZE_A4 26 +#define PAPER_SIZE_A3 27 +#define PAPER_SIZE_A2 28 +#define PAPER_SIZE_A1 29 +#define PAPER_SIZE_A0 30 + +/* Get the paper size code, based on width and height. */ +int gdev_pcl_paper_size(P1(gx_device *)); + +/* Color mapping procedures for 3-bit-per-pixel RGB printers */ +dev_proc_map_rgb_color(gdev_pcl_3bit_map_rgb_color); +dev_proc_map_color_rgb(gdev_pcl_3bit_map_color_rgb); + +/* Row compression routines */ +typedef ulong word; +int gdev_pcl_mode2compress(P3(const word * row, const word * end_row, byte * compressed)), + gdev_pcl_mode3compress(P4(int bytecount, const byte * current, byte * previous, byte * compressed)); + +#endif /* gdevpcl_INCLUDED */ diff --git a/pstoraster/gdevpdfx.h b/pstoraster/gdevpdfx.h new file mode 100644 index 0000000000..22dbf4dbc9 --- /dev/null +++ b/pstoraster/gdevpdfx.h @@ -0,0 +1,555 @@ +/* Copyright (C) 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Internal definitions for PDF-writing driver. */ + +#ifndef gdevpdfx_INCLUDED +# define gdevpdfx_INCLUDED + +#include "gsparam.h" +#include "gxdevice.h" +#include "gxline.h" +#include "stream.h" +#include "gdevpstr.h" +#include "gdevpsdf.h" + +/* ---------------- Statically allocated sizes ---------------- */ +/* These should all really be dynamic.... */ + +/* Define the maximum number of contents fragments on a page. */ +#define max_contents_ids 300 + +/* Define the maximum depth of an outline tree. */ +/* Note that there is no limit on the breadth of the tree. */ +#define max_outline_depth 8 + +/* Define the maximum size of a destination array string. */ +#define max_dest_string 80 + +/* ================ Types and structures ================ */ + +/* ---------------- Resources ---------------- */ + +typedef enum { + /* Standard PDF resources. */ + resourceFont, + resourceEncoding, + resourceFontDescriptor, + resourceColorSpace, + resourceImageXObject, + /* Internally used resources. */ + resourceCharProc, + resourceNamedObject, + num_resource_types +} pdf_resource_type; + +#define pdf_resource_type_names\ + "Font", "Encoding", "FontDescriptor", "ColorSpace", "XObject",\ + 0, 0, 0 +#define pdf_resource_type_structs\ + &st_pdf_font, &st_pdf_resource, &st_pdf_resource, &st_pdf_resource,\ + &st_pdf_resource, &st_pdf_char_proc, &st_pdf_named_object + +#define pdf_resource_common(typ)\ + typ *next; /* next resource of this type */\ + pdf_resource *prev; /* previously allocated resource */\ + gs_id rid; /* optional key */\ + long id +typedef struct pdf_resource_s pdf_resource; +struct pdf_resource_s { + pdf_resource_common(pdf_resource); +}; + +#define private_st_pdf_resource()\ + gs_private_st_ptrs2(st_pdf_resource, pdf_resource, "pdf_resource",\ + pdf_resource_enum_ptrs, pdf_resource_reloc_ptrs, next, prev) + +/* Font resources */ +typedef struct pdf_char_proc_s pdf_char_proc; /* forward reference */ +typedef struct pdf_font_s pdf_font; +typedef struct pdf_font_name_s { + byte chars[40]; /* arbitrary, must be large enough for */ + /* the 14 built-in fonts */ + uint size; +} pdf_font_name; +struct pdf_font_s { + pdf_resource_common(pdf_font); + pdf_font_name fname; + bool used_on_page; + char frname[6 + 1]; /* xxxxxx\0 */ + /* Encoding differences for base fonts. */ + byte chars_used[32]; /* 1 bit per character code */ + gs_const_string *differences; + long diff_id; + /* Bookkeeping for embedded fonts. */ + int num_chars; +#define font_is_embedded(font) ((font)->num_chars != 0) + pdf_char_proc *char_procs; + int max_y_offset; + /* Pseudo-characters for spacing. */ + /* The range should be determined by the device resolution.... */ +#define x_space_min 24 +#define x_space_max 150 + byte spaces[x_space_max - x_space_min + 1]; +}; + +#define private_st_pdf_font()\ + gs_private_st_suffix_add2(st_pdf_font, pdf_font, "pdf_font",\ + pdf_font_enum_ptrs, pdf_font_reloc_ptrs, st_pdf_resource,\ + differences, char_procs) + +/* CharProc pseudo-resources for embedded fonts */ +struct pdf_char_proc_s { + pdf_resource_common(pdf_char_proc); + pdf_font *font; + pdf_char_proc *char_next; /* next char_proc for same font */ + int width, height; + int x_width; /* X escapement */ + int y_offset; /* of character (0,0) */ + byte char_code; +}; + +#define private_st_pdf_char_proc()\ + gs_private_st_suffix_add2(st_pdf_char_proc, pdf_char_proc,\ + "pdf_char_proc", pdf_char_proc_enum_ptrs,\ + pdf_char_proc_reloc_ptrs, st_pdf_resource, font, char_next) + +/* Named object pseudo-resources. */ +/* + * The elements of arrays are stored sorted in decreasing index order. + * The elements of dictionaries are not sorted. + * The elements of streams don't use the key, and are stored in + * reverse order. + */ +typedef struct pdf_named_element_s pdf_named_element; +struct pdf_named_element_s { + pdf_named_element *next; + gs_string key; /* if array, data = 0, size = index */ + gs_string value; +}; +typedef enum { + named_unknown, /* forward reference */ + named_array, named_dict, named_stream, /* OBJ or predefined */ + named_graphics, /* BP/EP */ + named_other /* ANN, DEST, LNK, PS */ +} pdf_named_object_type; + +#define private_st_pdf_named_element() /* in gdevpdfo.c */\ + gs_private_st_composite(st_pdf_named_element, pdf_named_element,\ + "pdf_named_element", pdf_named_elt_enum_ptrs, pdf_named_elt_reloc_ptrs) +typedef struct pdf_named_object_s pdf_named_object; +struct pdf_named_object_s { + pdf_resource_common(pdf_named_object); + pdf_named_object_type type; + gs_string key; + pdf_named_element *elements; /* (extra key/value pairs for graphics) */ + bool open; /* stream, graphics */ + struct gr_ { /* graphics only */ + pdf_named_object *enclosing; + } graphics; +}; + +#define public_st_pdf_named_object() /* in gdevpdfo.c */\ + gs_public_st_composite(st_pdf_named_object, pdf_named_object,\ + "pdf_named_object", pdf_named_obj_enum_ptrs, pdf_named_obj_reloc_ptrs) + +/* ---------------- Other auxiliary structures ---------------- */ + +/* Outline nodes and levels */ +typedef struct pdf_outline_node_s { + long id, parent_id, prev_id, first_id, last_id; + int count; + gs_string action_string; +} pdf_outline_node; +typedef struct pdf_outline_level_s { + pdf_outline_node first; + pdf_outline_node last; + int left; +} pdf_outline_level; + +/* Articles */ +typedef struct pdf_bead_s { + long id, article_id, prev_id, next_id, page_id; + gs_rect rect; +} pdf_bead; +typedef struct pdf_article_s pdf_article; +struct pdf_article_s { + pdf_article *next; + gs_string title; + gs_string info; + long id; + pdf_bead first; + pdf_bead last; +}; + +#define private_st_pdf_article()\ + gs_private_st_ptrs1_strings2(st_pdf_article, pdf_article, "pdf_article",\ + pdf_article_enum_ptrs, pdf_article_reloc_ptrs, next, title, info) + +/* Named destinations */ +typedef struct pdf_named_dest_s pdf_named_dest; +struct pdf_named_dest_s { + pdf_named_dest *next; + gs_string key; + char dest[max_dest_string]; +}; + +#define private_st_pdf_named_dest()\ + gs_private_st_ptrs1_strings1(st_pdf_named_dest, pdf_named_dest,\ + "pdf_named_dest", pdf_named_dest_enum_ptrs, pdf_named_dest_reloc_ptrs,\ + next, key) + +/* ---------------- The device structure ---------------- */ + +/* Text state */ +typedef struct pdf_text_state_s { + /* State parameters */ + float character_spacing; + pdf_font *font; + floatp size; + float word_spacing; + float horizontal_scaling; + /* Bookkeeping */ + gs_matrix matrix; /* relative to device space, not user space */ + gs_point line_start; + gs_point current; +#define max_text_buffer 200 /* arbitrary, but overflow costs 5 chars */ + byte buffer[max_text_buffer]; + int buffer_count; +} pdf_text_state; + +#define pdf_text_state_default\ + 0, NULL, 0, 0, 100,\ + { identity_matrix_body }, { 0, 0 }, { 0, 0 }, { 0 }, 0 + +/* Resource lists */ +#define num_resource_chains 16 +typedef struct pdf_resource_list_s { + pdf_resource *chains[num_resource_chains]; +} pdf_resource_list; + +/* Define the hash function for gs_ids. */ +#define gs_id_hash(rid) ((rid) + ((rid) / num_resource_chains)) + +/* Define the bookkeeping for an open stream. */ +typedef struct pdf_stream_position_s { + long length_id; + long start_pos; +} pdf_stream_position; + +/* Define the device structure. */ +typedef enum { + NoMarks = 0, + ImageB = 1, + ImageC = 2, + ImageI = 4, + Text = 8 +} pdf_procset; +typedef enum { + pdf_in_none, + pdf_in_stream, + pdf_in_text, + pdf_in_string +} pdf_context; +typedef struct gx_device_pdf_s { + gx_device_psdf_common; + /* PDF-specific distiller parameters */ + float CompatibilityLevel; + /* End of distiller parameters */ + /* Other parameters */ + bool ReAssignCharacters; + bool ReEncodeCharacters; + long FirstObjectNumber; + /* End of parameters */ + /* Following are set when device is opened. */ + enum { + pdf_compress_none, + pdf_compress_LZW, /* not currently used, thanks to Unisys */ + pdf_compress_Flate + } compression; +#define pdf_memory v_memory + char tfname[gp_file_name_sizeof]; + FILE *tfile; + char rfname[gp_file_name_sizeof]; + FILE *rfile; + stream *rstrm; + byte *rstrmbuf; + stream *rsave_strm; + pdf_font *open_font; + long embedded_encoding_id; + /* ................ */ + long next_id; + /* The following 2 IDs, and only these, are allocated */ + /* when the file is opened. */ + long root_id; + long info_id; +#define pdf_num_initial_ids 2 + long pages_id; + long outlines_id; + int next_page; + long contents_id; + pdf_context context; + long contents_length_id; + long contents_pos; + pdf_procset procsets; /* used on this page */ + float flatness; +/****** SHOULD USE state ******/ + /* The line width, dash offset, and dash pattern */ + /* are in default user space units. */ + gx_line_params line_params; /* current values */ +/****** SHOULD USE state ******/ + pdf_text_state text; + long space_char_ids[x_space_max - x_space_min + 1]; +#define initial_num_page_ids 50 + long *page_ids; + int num_page_ids; + int pages_referenced; + pdf_resource_list resources[num_resource_types]; + pdf_resource *annots; /* rid = page # */ + pdf_resource *last_resource; + gs_string catalog_string; + gs_string pages_string; + gs_string page_string; + pdf_outline_level outline_levels[max_outline_depth]; + int outline_depth; + int closed_outline_depth; + int outlines_open; + pdf_article *articles; + pdf_named_dest *named_dests; + pdf_named_object *named_objects; + pdf_named_object *open_graphics; +} gx_device_pdf; + +#define is_in_page(pdev)\ + ((pdev)->contents_id != 0) +#define is_in_document(pdev)\ + (is_in_page(pdev) || (pdev)->last_resource != 0) + +/* Enumerate the individual pointers in a gx_device_pdf */ +#define gx_device_pdf_do_ptrs(m)\ + m(0,rstrm) m(1,rstrmbuf) m(2,rsave_strm) m(3,open_font)\ + m(4,line_params.dash.pattern) m(5,text.font) m(6,page_ids) m(7,annots)\ + m(8,last_resource) m(9,articles) m(10,named_dests)\ + m(11,named_objects) m(12,open_graphics) +#define gx_device_pdf_num_ptrs 13 /* + num_resource_types */ +#define gx_device_pdf_do_strings(m)\ + m(0,catalog_string) m(1,pages_string) m(2,page_string) +#define gx_device_pdf_num_strings 3 /* + max_outline_depth * 2 */ +#define st_device_pdf_max_ptrs\ + (st_device_psdf_max_ptrs + gx_device_pdf_num_ptrs +\ + gx_device_pdf_num_strings + num_resource_types * num_resource_chains +\ + max_outline_depth * 2) + +#define private_st_device_pdfwrite() /* in gdevpdf.c */\ + gs_private_st_composite_final(st_device_pdfwrite, gx_device_pdf,\ + "gx_device_pdf", device_pdfwrite_enum_ptrs, device_pdfwrite_reloc_ptrs,\ + device_pdfwrite_finalize) + +/* ================ Utility procedures ================ */ + +/* ---------------- Exported by gdevpdf.c ---------------- */ + +/* ------ Document ------ */ + +/* Initialize the IDs allocated at startup. */ +void pdf_initialize_ids(P1(gx_device_pdf * pdev)); + +/* Open the document if necessary. */ +void pdf_open_document(P1(gx_device_pdf * pdev)); + +/* ------ Objects ------ */ + +/* Allocate an ID for a future object. */ +long pdf_obj_ref(P1(gx_device_pdf * pdev)); + +/* Read the current position in the output stream. */ +long pdf_stell(P1(gx_device_pdf * pdev)); + +/* Begin an object, optionally allocating an ID. */ +long pdf_open_obj(P2(gx_device_pdf * pdev, long id)); + +/* Begin an object, allocating an ID. */ +#define pdf_begin_obj(pdev) pdf_open_obj(pdev, 0) + +/* End an object. */ +int pdf_end_obj(P1(gx_device_pdf * pdev)); + +/* ------ Graphics ------ */ + +/* Reset the graphics state parameters to initial values. */ +void pdf_reset_graphics(P1(gx_device_pdf * pdev)); + +/* Set the fill or stroke color. */ +int pdf_set_color(P4(gx_device_pdf * pdev, gx_color_index color, + gx_drawing_color * pdcolor, const char *rgs)); + +/* Write matrix values. */ +void pdf_put_matrix(P4(gx_device_pdf * pdev, const char *before, + const gs_matrix * pmat, const char *after)); + +/* Write a name, with escapes for unusual characters. */ +void pdf_put_name(P3(const gx_device_pdf * pdev, const byte * nstr, uint size)); + +/* Write a string in its shortest form ( () or <> ). */ +void pdf_put_string(P3(const gx_device_pdf * pdev, const byte * str, uint size)); + +/* Write a value, treating names specially. */ +void pdf_put_value(P3(const gx_device_pdf * pdev, const byte * vstr, uint size)); + +/* ------ Page contents ------ */ + +/* Open a page contents part. */ +/* Return an error if the page has too many contents parts. */ +int pdf_open_contents(P2(gx_device_pdf * pdev, pdf_context context)); + +/* Close the current contents part if we are in one. */ +int pdf_close_contents(P2(gx_device_pdf * pdev, bool last)); + +/* ------ Resources et al ------ */ + +/* Begin an object logically separate from the contents. */ +/* (I.e., an object in the resource file.) */ +long pdf_open_separate(P2(gx_device_pdf * pdev, long id)); + +#define pdf_begin_separate(pdev) pdf_open_separate(pdev, 0L) + +/* Begin an aside (resource, annotation, ...). */ +int pdf_begin_aside(P4(gx_device_pdf * pdev, pdf_resource ** plist, + const gs_memory_struct_type_t * pst, + pdf_resource ** ppres)); + +/* Begin a resource of a given type. */ +int pdf_begin_resource(P4(gx_device_pdf * pdev, pdf_resource_type type, + gs_id rid, pdf_resource ** ppres)); + +/* Allocate a resource, but don't open the stream. */ +int pdf_alloc_resource(P4(gx_device_pdf * pdev, pdf_resource_type type, + gs_id rid, pdf_resource ** ppres)); + +/* Find a resource of a given type by gs_id. */ +pdf_resource *pdf_find_resource_by_gs_id(P3(gx_device_pdf * pdev, + pdf_resource_type type, + gs_id rid)); + +/* End a separate object. */ +#define pdf_end_separate(pdev) pdf_end_aside(pdev) + +/* End an aside. */ +int pdf_end_aside(P1(gx_device_pdf * pdev)); + +/* End a resource. */ +int pdf_end_resource(P1(gx_device_pdf * pdev)); + +/* ------ Pages ------ */ + +/* Get or assign the ID for a page. */ +/* Returns 0 if the page number is out of range. */ +long pdf_page_id(P2(gx_device_pdf * pdev, int page_num)); + +/* Open a page for writing. */ +int pdf_open_page(P2(gx_device_pdf * pdev, pdf_context context)); + +/* Write saved page- or document-level information. */ +int pdf_write_saved_string(P2(gx_device_pdf * pdev, gs_string * pstr)); + +/* Write the default entries of the Info dictionary. */ +int pdf_write_default_info(P1(gx_device_pdf * pdev)); + +/* ------ Path drawing ------ */ + +bool pdf_must_put_clip_path(P2(gx_device_pdf * pdev, const gx_clip_path * pcpath)); + +int pdf_put_clip_path(P2(gx_device_pdf * pdev, const gx_clip_path * pcpath)); + +/* ---------------- Exported by gdevpdfm.c ---------------- */ + +/* Compare a C string and a gs_param_string. */ +bool pdf_key_eq(P2(const gs_param_string * pcs, const char *str)); + +/* Scan an integer out of a parameter string. */ +int pdfmark_scan_int(P2(const gs_param_string * pstr, int *pvalue)); + +/* Define the type for a pdfmark-processing procedure. */ +/* If nameable is false, the objname argument is always NULL. */ +#define pdfmark_proc(proc)\ + int proc(P5(gx_device_pdf *pdev, gs_param_string *pairs, uint count,\ + const gs_matrix *pctm, const gs_param_string *objname)) +/* Define an entry in a table of pdfmark-processing procedures. */ +#define pdfmark_nameable 1 /* allows _objdef */ +#define pdfmark_odd_ok 2 /* OK if odd # of parameters */ +#define pdfmark_keep_name 4 /* don't substitute reference for name */ + /* in 1st argument */ +typedef struct pdfmark_name_s { + const char *mname; + pdfmark_proc((*proc)); + byte options; +} pdfmark_name; + +/* Process a pdfmark (called from pdf_put_params). */ +int pdfmark_process(P2(gx_device_pdf * pdev, const gs_param_string_array * pma)); + +/* Close the current level of the outline tree. */ +int pdfmark_close_outline(P1(gx_device_pdf * pdev)); + +/* Finish writing an article. */ +int pdfmark_write_article(P2(gx_device_pdf * pdev, const pdf_article * part)); + +/* ---------------- Exported by gdevpdfo.c ---------------- */ + +/* Define the syntax of object names. */ +#define pdfmark_objname_is_valid(data, size)\ + ((size) >= 2 && (data)[0] == '{' &&\ + memchr(data, '}', size) == (data) + (size) - 1) + +/* Define the table of named-object pdfmark types. */ +extern const pdfmark_name pdfmark_names_named[]; + +/* Replace object names with object references in a (parameter) string. */ +int pdfmark_replace_names(P3(gx_device_pdf * pdev, const gs_param_string * from, + gs_param_string * to)); + +/* Write and free an entire list of named objects. */ +int pdfmark_write_and_free_named(P2(gx_device_pdf * pdev, + pdf_named_object ** ppno)); + +/* ---------------- Exported by gdevpdft.c ---------------- */ + +/* Process a show operation (called from pdf_put_params). */ +int pdfshow_process(P3(gx_device_pdf * pdev, gs_param_list * plist, + const gs_param_string * pts)); + +/* Begin a CharProc for an embedded (bitmap) font. */ +int pdf_begin_char_proc(P8(gx_device_pdf * pdev, int w, int h, int x_width, + int y_offset, gs_id id, pdf_char_proc ** ppcp, + pdf_stream_position * ppos)); + +/* End a CharProc. */ +int pdf_end_char_proc(P2(gx_device_pdf * pdev, pdf_stream_position * ppos)); + +/* Put out a reference to an image as a character in an embedded font. */ +int pdf_do_char_image(P3(gx_device_pdf * pdev, const pdf_char_proc * pcp, + const gs_matrix * pimat)); + +#endif /* gdevpdfx_INCLUDED */ diff --git a/pstoraster/gdevpipe.c b/pstoraster/gdevpipe.c new file mode 100644 index 0000000000..03909db6a7 --- /dev/null +++ b/pstoraster/gdevpipe.c @@ -0,0 +1,72 @@ +/* Copyright (C) 1993, 1994, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* %pipe% IODevice */ +#include "errno_.h" +#include "pipe_.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" + +/* The pipe IODevice */ +private iodev_proc_fopen(pipe_fopen); +private iodev_proc_fclose(pipe_fclose); +const 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/gdevpm.h b/pstoraster/gdevpm.h new file mode 100644 index 0000000000..f1f7b3cd88 --- /dev/null +++ b/pstoraster/gdevpm.h @@ -0,0 +1,46 @@ +/* Copyright (C) 1992, 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Defines common to gdevpm.c, gspmdrv.c and PM GSview */ + +#ifndef gdevpm_INCLUDED +# define gdevpm_INCLUDED + +#define SHARED_NAME "\\SHAREMEM\\%s" +#define SYNC_NAME "\\SEM32\\SYNC_%s" +#define NEXT_NAME "\\SEM32\\NEXT_%s" +#define MUTEX_NAME "\\SEM32\\MUTEX_%s" +#define QUEUE_NAME "\\QUEUES\\%s" + +#define GS_UPDATING 1 +#define GS_SYNC 2 +#define GS_PAGE 3 +#define GS_CLOSE 4 +#define GS_ERROR 5 +#define GS_PALCHANGE 6 +#define GS_BEGIN 7 +#define GS_END 8 + +#endif /* gdevpm_INCLUDED */ diff --git a/pstoraster/gdevprn.c b/pstoraster/gdevprn.c new file mode 100644 index 0000000000..7a28c2c651 --- /dev/null +++ b/pstoraster/gdevprn.c @@ -0,0 +1,923 @@ +/* + Copyright 1993-2000 by Easy Software Products. + Copyright 1990, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Generic printer driver support */ +#include "ctype_.h" +#include "gdevprn.h" +#include "gp.h" +#include "gsparam.h" +#include "gxclio.h" +#include + +/* ---------------- Standard device procedures ---------------- */ + +/* Define the standard printer procedure vector. */ +const gx_device_procs prn_std_procs = + prn_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close); + +/* Forward references */ +int gdev_prn_maybe_reallocate_memory(P4(gx_device_printer *pdev, + gdev_prn_space_params *old_space, + int old_width, int old_height)); + +/* ------ Open/close ------ */ + +/* Open a generic printer device. */ +/* Specific devices may wish to extend this. */ +int +gdev_prn_open(gx_device * pdev) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + int code; + + ppdev->file = NULL; + code = gdev_prn_allocate_memory(pdev, NULL, 0, 0); + if (code < 0) + return code; + if (ppdev->OpenOutputFile) + code = gdev_prn_open_printer(pdev, 1); + return code; +} + +/* Generic closing for the printer device. */ +/* Specific devices may wish to extend this. */ +int +gdev_prn_close(gx_device * pdev) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + + gdev_prn_free_memory(pdev); + if (ppdev->file != NULL) { + if (ppdev->file != stdout) + gp_close_printer(ppdev->file, ppdev->fname); + ppdev->file = NULL; + } + return 0; +} + +private int /* returns 0 ok, else -ve error cde */ +gdev_prn_setup_as_command_list(gx_device *pdev, gs_memory_t *buffer_memory, + byte **the_memory, + const gdev_prn_space_params *space_params, + bool bufferSpace_is_exact) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + uint space; + int code; + gx_device_clist *const pclist_dev = (gx_device_clist *)pdev; + gx_device_clist_common * const pcldev = &pclist_dev->common; + bool reallocate = *the_memory != 0; + byte *base; + + /* Try to allocate based simply on param-requested buffer size */ + for ( space = space_params->BufferSpace; ; ) { + base = (reallocate ? + gs_resize_object(buffer_memory, *the_memory, space, + "cmd list buffer") : + gs_alloc_bytes(buffer_memory, space, + "cmd list buffer")); + if (base != 0) + break; + if (bufferSpace_is_exact || (space >>= 1) < PRN_MIN_BUFFER_SPACE) + break; + } + if (base == 0) + return_error(gs_error_VMerror); + *the_memory = base; + + /* Try opening the command list, to see if we allocated */ + /* enough buffer space. */ +open_c: + ppdev->buf = base; + ppdev->buffer_space = space; + clist_init_params(pclist_dev, base, space, pdev, + ppdev->printer_procs.make_buffer_device, + space_params->band, ppdev->is_async_renderer, + (ppdev->bandlist_memory == 0 ? &gs_memory_default : + ppdev->bandlist_memory), + ppdev->free_up_bandlist_memory, + ppdev->clist_disable_mask); + 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 >= space_params->BufferSpace && + !bufferSpace_is_exact + ) { + space <<= 1; + if (reallocate) { + base = gs_resize_object(buffer_memory, + *the_memory, space, + "cmd list buf(retry open)"); + if (base != 0) + *the_memory = base; + } else { + gs_free_object(buffer_memory, base, + "cmd list buf(retry open)"); + *the_memory = base = + gs_alloc_bytes(buffer_memory, space, + "cmd list buf(retry open)"); + } + ppdev->buf = *the_memory; + if (base != 0) + goto open_c; + } + /* Failure. */ + if (!reallocate) { + gs_free_object(buffer_memory, base, "cmd list buf"); + ppdev->buffer_space = 0; + *the_memory = 0; + } + } + return code; +} + +private bool /* ret true if device was cmd list, else false */ +gdev_prn_tear_down(gx_device *pdev, byte **the_memory) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + gx_device_memory * const pmemdev = (gx_device_memory *)pdev; + gx_device_clist *const pclist_dev = (gx_device_clist *)pdev; + gx_device_clist_common * const pcldev = &pclist_dev->common; + bool is_command_list; + + if (ppdev->buffer_space != 0) { + /* Close cmd list device & point to the storage */ + (*gs_clist_device_procs.close_device)( (gx_device *)pcldev ); + *the_memory = ppdev->buf; + ppdev->buf = 0; + ppdev->buffer_space = 0; + is_command_list = true; + } else { + /* point at the device bitmap, no need to close mem dev */ + *the_memory = pmemdev->base; + pmemdev->base = 0; + is_command_list = false; + } + + /* Reset device proc vector to default */ + if (ppdev->orig_procs.open_device != 0) + pdev->procs = ppdev->orig_procs; + ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */ + + return is_command_list; +} + +private int +gdev_prn_allocate(gx_device *pdev, gdev_prn_space_params *new_space_params, + int new_width, int new_height, bool reallocate) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + gx_device_memory * const pmemdev = (gx_device_memory *)pdev; + byte *the_memory = 0; + gdev_prn_space_params save_params; + int save_width, save_height; + bool is_command_list; + bool save_is_command_list; + int ecode = 0; + int pass; + gs_memory_t *buffer_memory = + (ppdev->buffer_memory == 0 ? &gs_memory_default : + ppdev->buffer_memory); + + /* If reallocate, find allocated memory & tear down buffer device */ + if (reallocate) + save_is_command_list = gdev_prn_tear_down(pdev, &the_memory); + + /* Re/allocate memory */ + ppdev->orig_procs = pdev->procs; + for ( pass = 1; pass <= (reallocate ? 2 : 1); ++pass ) { + ulong mem_space; + byte *base = 0; + bool bufferSpace_is_default = false; + gdev_prn_space_params space_params = ppdev->space_params; + + if (reallocate) + switch (pass) + { + case 1: + /* Setup device to get reallocated */ + save_params = ppdev->space_params; + ppdev->space_params = *new_space_params; + save_width = ppdev->width; + ppdev->width = new_width; + save_height = ppdev->height; + ppdev->height = new_height; + break; + case 2: /* only comes here if reallocate */ + /* Restore device to previous contents */ + ppdev->space_params = save_params; + ppdev->width = save_width; + ppdev->height = save_height; + break; + } + + /* Init clist/mem device-specific fields */ + memset(ppdev->skip, 0, sizeof(ppdev->skip)); + mem_space = gdev_mem_bitmap_size(pmemdev); + + /* Compute desired space params: never use the space_params as-is. */ + /* Rather, give the dev-specific driver a chance to adjust them. */ + space_params.BufferSpace = 0; + (*ppdev->printer_procs.get_space_params)(ppdev, &space_params); + if (ppdev->is_async_renderer && space_params.band.BandBufferSpace != 0) + space_params.BufferSpace = space_params.band.BandBufferSpace; + else if (space_params.BufferSpace == 0) { + if (space_params.band.BandBufferSpace > 0) + space_params.BufferSpace = space_params.band.BandBufferSpace; + else { + space_params.BufferSpace = ppdev->space_params.BufferSpace; + bufferSpace_is_default = true; + } + } + + /* Determine if we can use a full bitmap buffer, or have to use banding */ + if (pass > 1) + is_command_list = save_is_command_list; + else { + is_command_list = space_params.banding_type == BandingAlways || + mem_space >= space_params.MaxBitmap || + mem_space != (uint)mem_space; /* too big to allocate */ + } + if (!is_command_list) { + /* Try to allocate memory for full memory buffer */ + base = reallocate + ? gs_resize_object( buffer_memory, the_memory, + (uint)mem_space, "printer buffer" ) + : gs_alloc_bytes( buffer_memory, (uint)mem_space, + "printer_buffer" ); + if (base == 0) + is_command_list = true; + else + the_memory = base; + } + if (!is_command_list && pass == 1 && PRN_MIN_MEMORY_LEFT != 0 + && buffer_memory == &gs_memory_default) { + /* before using full memory buffer, ensure enough working mem left */ + byte * left = gs_alloc_bytes( buffer_memory, + PRN_MIN_MEMORY_LEFT, "printer mem left"); + if (left == 0) + is_command_list = true; + else + gs_free_object(buffer_memory, left, "printer mem left"); + } + + if (is_command_list) { + /* Buffer the image in a command list. */ + /* Release the buffer if we allocated it. */ + int code; + if (!reallocate) { + gs_free_object(buffer_memory, the_memory, + "printer buffer(open)"); + the_memory = 0; + } + if (space_params.banding_type == BandingNever) { + ecode = gs_note_error(gs_error_VMerror); + continue; + } + code = gdev_prn_setup_as_command_list(pdev, buffer_memory, + &the_memory, &space_params, + !bufferSpace_is_default); + if (ecode == 0) + ecode = code; + + if ( code >= 0 || (reallocate && pass > 1) ) + ppdev->procs = gs_clist_device_procs; + } else { + /* Render entirely in memory. */ + int code; + + ppdev->buffer_space = 0; + code = (*ppdev->printer_procs.make_buffer_device) + (pmemdev, pdev, buffer_memory, false); + if (code < 0) { /* Catastrophic. Shouldn't ever happen */ + gs_free_object(buffer_memory, base, "printer buffer"); + pdev->procs = ppdev->orig_procs; + ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */ + return_error(code); + } + pmemdev->base = base; + } + if (ecode == 0) + break; + } + + if (ecode >= 0 || reallocate) { /* even if realloc failed */ + /* 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); + COPY_PROC(get_clipping_box); + COPY_PROC(map_color_rgb_alpha); + COPY_PROC(get_hardware_params); +#undef COPY_PROC + /* If using a command list, already opened the device. */ + if (is_command_list) + return ecode; + else + return (*dev_proc(pdev, open_device))(pdev); + } else { + pdev->procs = ppdev->orig_procs; + ppdev->orig_procs.open_device = 0; /* prevent uninit'd restore of procs */ + return ecode; + } +} + +int +gdev_prn_allocate_memory(gx_device *pdev, + gdev_prn_space_params *new_space_params, + int new_width, int new_height) +{ + return gdev_prn_allocate(pdev, new_space_params, + new_width, new_height, false); +} + +int +gdev_prn_reallocate_memory(gx_device *pdev, + gdev_prn_space_params *new_space_params, + int new_width, int new_height) +{ + return gdev_prn_allocate(pdev, new_space_params, + new_width, new_height, true); +} + +int +gdev_prn_free_memory(gx_device *pdev) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + byte *the_memory = 0; + gs_memory_t *buffer_memory = + (ppdev->buffer_memory == 0 ? &gs_memory_default : + ppdev->buffer_memory); + + gdev_prn_tear_down(pdev, &the_memory); + gs_free_object(buffer_memory, the_memory, "gdev_prn_free_memory"); + return 0; +} + +/* ------------- Stubs related only to async rendering ------- */ + +int /* rets 0 ok, -ve error if couldn't start thread */ +gx_default_start_render_thread(gdev_prn_start_render_params *params) +{ + return gs_error_unknownerror; +} + +/* Open the renderer's copy of a device. */ +/* This is overriden in gdevprna.c */ +int +gx_default_open_render_device(gx_device_printer *pdev) +{ + return gs_error_unknownerror; +} + +/* Close the renderer's copy of a device. */ +int +gx_default_close_render_device(gx_device_printer *pdev) +{ + return gdev_prn_close( (gx_device *)pdev ); +} + +/* ------ 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) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + int code = gx_default_get_params(pdev, plist); + gs_param_string ofns; + + if (code < 0 || + (code = param_write_long(plist, "MaxBitmap", &ppdev->space_params.MaxBitmap)) < 0 || + (code = param_write_long(plist, "BufferSpace", &ppdev->space_params.BufferSpace)) < 0 || + (code = param_write_int(plist, "BandWidth", &ppdev->space_params.band.BandWidth)) < 0 || + (code = param_write_int(plist, "BandHeight", &ppdev->space_params.band.BandHeight)) < 0 || + (code = param_write_long(plist, "BandBufferSpace", &ppdev->space_params.band.BandBufferSpace)) < 0 || + (code = param_write_bool(plist, "OpenOutputFile", &ppdev->OpenOutputFile)) < 0 || + (code = param_write_bool(plist, "ReopenPerPage", &ppdev->ReopenPerPage)) < 0 || + (ppdev->Duplex_set >= 0 && + (code = (ppdev->Duplex_set ? + param_write_bool(plist, "Duplex", &ppdev->Duplex) : + param_write_null(plist, "Duplex"))) < 0) + ) + return code; + + ofns.data = (const byte *)ppdev->fname, + ofns.size = strlen(ppdev->fname), + ofns.persistent = false; + return param_write_string(plist, "OutputFile", &ofns); +} + +/* Validate an OutputFile name by checking any %-formats. */ +private int +validate_output_file(const gs_param_string * ofs) +{ + const byte *data = ofs->data; + uint size = ofs->size; + bool have_format = false; + uint i; + + if (size >= prn_fname_sizeof) + return_error(gs_error_limitcheck); + for (i = 0; i < size; ++i) + if (data[i] == '%') { + if (i + 1 < size && data[i + 1] == '%') + continue; + if (have_format) /* more than one % */ + return_error(gs_error_rangecheck); + have_format = true; + sw:if (++i == size) + return_error(gs_error_rangecheck); + switch (data[i]) { + case ' ': + 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: + return_error(gs_error_rangecheck); + } + } + return 0; +} + +/* Put parameters. */ +int +gdev_prn_put_params(gx_device * pdev, gs_param_list * plist) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + int ecode = 0; + int code; + const char *param_name; + bool is_open = pdev->is_open; + bool oof = ppdev->OpenOutputFile; + bool rpp = ppdev->ReopenPerPage; + bool duplex; + int duplex_set = -1; + int width = pdev->width; + int height = pdev->height; + gdev_prn_space_params sp, save_sp; + gs_param_string ofs; + gs_param_dict mdict; + + sp = ppdev->space_params; + save_sp = sp; + + 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; + } + + switch (code = param_read_bool(plist, (param_name = "ReopenPerPage"), &rpp)) { + 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: + ; + } +#define CHECK_PARAM_CASES(member, bad, label)\ + case 0:\ + if ((sp.params_are_read_only ? sp.member != save_sp.member : bad))\ + ecode = gs_error_rangecheck;\ + else\ + break;\ + goto label;\ + default:\ + ecode = code;\ +label:\ + param_signal_error(plist, param_name, ecode);\ + case 1:\ + break + + switch (code = param_read_long(plist, (param_name = "MaxBitmap"), &sp.MaxBitmap)) { + CHECK_PARAM_CASES(MaxBitmap, sp.MaxBitmap < 10000, mbe); + } + + switch (code = param_read_long(plist, (param_name = "BufferSpace"), &sp.BufferSpace)) { + CHECK_PARAM_CASES(BufferSpace, sp.BufferSpace < 10000, bse); + } + + switch (code = param_read_int(plist, (param_name = "BandWidth"), &sp.band.BandWidth)) { + CHECK_PARAM_CASES(band.BandWidth, sp.band.BandWidth < 0, bwe); + } + + switch (code = param_read_int(plist, (param_name = "BandHeight"), &sp.band.BandHeight)) { + CHECK_PARAM_CASES(band.BandHeight, sp.band.BandHeight < 0, bhe); + } + + switch (code = param_read_long(plist, (param_name = "BandBufferSpace"), &sp.band.BandBufferSpace)) { + CHECK_PARAM_CASES(band.BandBufferSpace, sp.band.BandBufferSpace < 0, bbse); + } + + switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofs)) { + case 0: + code = validate_output_file(&ofs); + if (code >= 0) + break; + /* falls through */ + default: + ecode = code; + 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->OpenOutputFile = oof; + ppdev->ReopenPerPage = rpp; + if (duplex_set >= 0) { + ppdev->Duplex = duplex; + ppdev->Duplex_set = duplex_set; + } + ppdev->space_params = sp; + + /* If necessary, free and reallocate the printer memory. */ + /* Formerly, would not reallocate if device is not open: */ + /* we had to patch this out (see News for 5.50). */ + code = gdev_prn_maybe_reallocate_memory(ppdev, &save_sp, width, height); + if (code < 0) + return code; + + /* If filename changed, close file. */ + 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; +} + +/* ------ Others ------ */ + +/* Default routine to (not) override current space_params. */ +void +gdev_prn_default_get_space_params(const gx_device_printer *printer_dev, + gdev_prn_space_params *space_params) +{ + return; +} + +/* Generic routine to send the page to the printer. */ +int /* 0 ok, -ve error, or 1 if successfully upgraded to buffer_page */ +gdev_prn_output_page(gx_device * pdev, int num_copies, int flush) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + int outcode = 0, closecode = 0, errcode = 0, endcode; + bool upgraded_copypage = false; + + if (num_copies > 0 || !flush) { + int code = gdev_prn_open_printer(pdev, 1); + + if (code < 0) + return code; + + /* If copypage request, try to do it using buffer_page */ + if ( !flush && + (*ppdev->printer_procs.buffer_page) + (ppdev, ppdev->file, num_copies) >= 0 + ) { + upgraded_copypage = true; + flush = true; + } + else if (num_copies > 0) + /* Print the accumulated page description. */ + outcode = + (*ppdev->printer_procs.print_page_copies)(ppdev, ppdev->file, + num_copies); + if (ppdev->file) + { + fflush(ppdev->file); + errcode = + (ferror(ppdev->file) ? gs_note_error(gs_error_ioerror) : 0); + } + else + errcode = 0; + + if (!upgraded_copypage) + closecode = gdev_prn_close_printer(pdev); + } + endcode = (ppdev->buffer_space ? clist_finish_page(pdev, flush) : 0); + + if (outcode < 0) + return outcode; + if (errcode < 0) + return errcode; + if (closecode < 0) + return closecode; + if (endcode < 0) + return endcode; + return (upgraded_copypage ? 1 : 0); +} + +/* 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; +} + +/* + * Buffer a (partial) rasterized page & optionally print result multiple times. + * The default implementation returns error, since the driver needs to override + * this (in procedure vector) in configurations where this call may occur. + */ +int +gx_default_buffer_page(gx_device_printer *pdev, FILE *prn_stream, + int num_copies) +{ + return gs_error_unknownerror; +} + +/* ---------------- 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_positionable(gx_device *pdev, bool binary_mode, + bool positionable) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + + if (ppdev->file != 0) { + ppdev->file_is_new = false; + return 0; + } + { + int code = gx_device_open_output_file(pdev, ppdev->fname, + binary_mode, positionable, + &ppdev->file); + if (code < 0) + return code; + } + ppdev->file_is_new = true; + return 0; +} +int +gdev_prn_open_printer(gx_device *pdev, bool binary_mode) +{ + return gdev_prn_open_printer_positionable(pdev, binary_mode, false); +} + +/* 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; +} + +/* Like get_bits, but accepts initial raster contents */ +int +gdev_prn_get_overlay_bits(gx_device_printer *pdev, int y, int lineCount, + byte *data) +{ + if (pdev->buffer_space) { + /* Command lists have built-in support for this function */ + return clist_get_overlay_bits(pdev, y, lineCount, data); + } else { + /* Memory devices cannot support this function. */ + return_error(gs_error_unknownerror); + } +} + +/* Find out where the band buffer for a given line is going to fall on the */ +/* next call to get_bits. */ +int /* rets # lines from y till end of buffer, or -ve error code */ +gdev_prn_locate_overlay_buffer(gx_device_printer *pdev, int y, byte **data) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + + if (ppdev->buffer_space) { + /* Command lists have built-in support for this function */ + return clist_locate_overlay_buffer(pdev, y, data); + } else { + /* Memory devices cannot support this function. */ + return_error(gs_error_unknownerror); + } +} + +/* Close the current page. */ +int +gdev_prn_close_printer(gx_device * pdev) +{ + gx_device_printer * const ppdev = (gx_device_printer *)pdev; + + if (strchr(ppdev->fname, '%') /* file per page */ || + ppdev->ReopenPerPage /* close and reopen for each page */ + ) { + gp_close_printer(ppdev->file, ppdev->fname); + ppdev->file = NULL; + } + return 0; +} + +/* If necessary, free and reallocate the printer memory after changing params */ +int +gdev_prn_maybe_reallocate_memory(gx_device_printer *prdev, + gdev_prn_space_params *old_sp, + int old_width, int old_height) +{ + int code = 0; + gx_device *const pdev = (gx_device *)prdev; + gx_device_memory * const mdev = (gx_device_memory *)prdev; + + /* The first test here used to be prdev->open. See News for 5.50. */ + if (mdev->base != 0 && + (memcmp(&prdev->space_params, old_sp, sizeof(*old_sp)) != 0 || + prdev->width != old_width || prdev->height != old_height ) + ) { + int new_width = prdev->width; + int new_height = prdev->height; + gdev_prn_space_params new_sp = prdev->space_params; + + prdev->width = old_width; + prdev->height = old_height; + prdev->space_params = *old_sp; + code = gdev_prn_reallocate_memory(pdev, &new_sp, + new_width, new_height); + /* If this fails, device should be usable w/old params, but */ + /* band files may not be open. */ + } + return code; +} diff --git a/pstoraster/gdevprn.h b/pstoraster/gdevprn.h new file mode 100644 index 0000000000..68c09d6b5e --- /dev/null +++ b/pstoraster/gdevprn.h @@ -0,0 +1,560 @@ +/* Copyright (C) 1989, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Common header file for memory-buffered printers */ + +#ifndef gdevprn_INCLUDED +# define gdevprn_INCLUDED + +#include "memory_.h" +#include "string_.h" +#include "gx.h" +#include "gp.h" /* for gp_file_name_sizeof */ +#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 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. */ +#ifndef gx_device_printer_DEFINED +# define gx_device_printer_DEFINED +typedef struct gx_device_printer_s gx_device_printer; +#endif + +/* Define the abstract type for some band device procedures' arguments. */ +typedef struct gdev_prn_start_render_params_s gdev_prn_start_render_params; + +/* Define the abstract type for a page queue for async rendering. */ +#ifndef gx_page_queue_DEFINED +# define gx_page_queue_DEFINED +typedef struct gx_page_queue_s gx_page_queue; +#endif + +/* Define the abstract type for parameters describing buffer space. */ +#ifndef gdev_prn_space_params_DEFINED +# define gdev_prn_space_params_DEFINED +typedef struct gdev_prn_space_params_s gdev_prn_space_params; +#endif + +/* + * 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 prn_dev_proc_print_page(proc)\ + int proc(P2(gx_device_printer *, FILE *)) + prn_dev_proc_print_page((*print_page)); +/* BACKWARD COMPATIBILITY */ +#define dev_proc_print_page(proc) prn_dev_proc_print_page(proc) + + /* Print the page on the output file, with a given # of copies. */ + +#define prn_dev_proc_print_page_copies(proc)\ + int proc(P3(gx_device_printer *, FILE *, int)) + prn_dev_proc_print_page_copies((*print_page_copies)); +/* BACKWARD COMPATIBILITY */ +#define dev_proc_print_page_copies(proc) prn_dev_proc_print_page_copies(proc) + + /* Initialize the memory device for a page or a band. */ + /* (The macro definition is in gxdevcli.h.) */ + + dev_proc_make_buffer_device((*make_buffer_device)); + + /* + * Compute effective space params. These results effectively override + * the space_params in the device, but does not replace them; that is to + * say that computed space params are temps used for computation. + * Procedure must fill in only those space_params that it wishes to + * override, using curr width, height, margins, etc. + * + * Caller is gdevprn.open & gdevprn.put_params, calls driver or + * default. + */ + +#define prn_dev_proc_get_space_params(proc)\ + void proc(P2(const gx_device_printer *, gdev_prn_space_params *)) + prn_dev_proc_get_space_params((*get_space_params)); + + /* + * Only for gx_device_printer devices that overlap interpreting and + * rasterizing. Since there are 2 instances of the device (1 for writing + * the cmd list & 1 for rasterizing it), and each device is associated + * with an different thread, this function is called to start the + * rasterizer's thread. Once started, the rasterizer thread must call + * down to gdev_prn_asnyc_render_thread, which will only return after + * device closes. + * + * Caller is gdevprna.open, calls driver implementation or default. + */ + +#define prn_dev_proc_start_render_thread(proc)\ + int proc(P1(gdev_prn_start_render_params *)) + prn_dev_proc_start_render_thread((*start_render_thread)); + + /* + * Only for gx_device_printer devices that overlap interpreting and + * rasterizing. Since there are 2 instances of the device (1 for writing + * the cmd list & 1 for rasterizing it), these fns are called to + * open/close the rasterizer's instance, once the writer's instance has + * been created & init'd. These procs must cascade down to + * gdev_prn_async_render_open/close. + * + * Caller is gdevprna, calls driver implementation or default. + */ + +#define prn_dev_proc_open_render_device(proc)\ + int proc(P1(gx_device_printer *)) + prn_dev_proc_open_render_device((*open_render_device)); + +#define prn_dev_proc_close_render_device(proc)\ + int proc(P1(gx_device_printer *)) + prn_dev_proc_close_render_device((*close_render_device)); + + /* + * Buffer a page on the output device. A page may or may not have been + * fully rendered, but the rasterizer needs to realize the page to free + * up resources or support copypage. Printing a page may involve zero or + * more buffer_pages. All buffer_page output is overlaid in the buffer + * until a terminating print_page or print_page_copies clears the + * buffer. Note that, after the first buffer_page, the driver must use + * the get_overlay_bits function instead of get_bits. The difference is + * that get_overlay_bits requires the caller to supply the same buffered + * bitmap that was computed as a result of a previous buffer_page, so + * that get_overlay_bits can add further marks to the existing buffered + * image. NB that output must be accumulated in buffer even if + * num_copies == 0. + * + * Caller is expected to be gdevprn, calls driver implementation or + * default. + */ + +#define prn_dev_proc_buffer_page(proc)\ + int proc(P3(gx_device_printer *, FILE *, int)) + prn_dev_proc_buffer_page((*buffer_page)); + + /* + * Transform a given set of bits by marking it per the current page + * description. This is a different version of get_bits, where this + * procedure accepts a bitmap and merely adds further marks, without + * clearing the bits. + * + * Driver implementation is expected to be the caller. + */ + +#define prn_dev_proc_get_overlay_bits(proc)\ + int proc(P4(gx_device_printer *, int, int, byte *)) + prn_dev_proc_get_overlay_bits((*get_overlay_bits)); + + /* + * Find out where the band buffer for a given line is going to fall on + * the next call to get_bits. This is an alternative to get_overlay_bits + * in cases where the client doesn't own a suitably formatted buffer to + * deposit bits into. When using this function, do a + * locate_overlay_buffer, copy the background data into the returned + * buffer, then do get_bits to get the transformed data. IMPORTANT: the + * locate_overlay_buffer for a specific range of lines must immediately + * be followed by one or more get_bits for the same line range with no + * other intervening driver calls. If this condition is violated, + * results are undefined. + */ + +#define prn_dev_proc_locate_overlay_buffer(proc)\ + int proc(P3(gx_device_printer *, int, byte **)) + prn_dev_proc_locate_overlay_buffer((*locate_overlay_buffer)); + +} 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 gp_file_name_sizeof +typedef enum { + BandingAuto = 0, + BandingAlways, + BandingNever +} gdev_prn_banding_type; +struct gdev_prn_space_params_s { + long MaxBitmap; /* max size of non-buffered bitmap */ + long BufferSpace; /* space to use for buffer */ + gx_band_params band; /* see gxclist.h */ + bool params_are_read_only; /* true if put_params may not modify this struct */ + gdev_prn_banding_type banding_type; /* used to force banding or bitmap */ +}; + +#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;\ + /* ------ Device parameters that must be set ------ */\ + /* ------ before calling the device open routine. ------ */\ + gdev_prn_space_params space_params;\ + char fname[prn_fname_sizeof]; /* OutputFile */\ + /* ------ Other device parameters ------ */\ + bool OpenOutputFile;\ + bool ReopenPerPage;\ + bool Duplex;\ + int Duplex_set; /* -1 = not supported */\ + /* ------ End of parameters ------ */\ + bool file_is_new; /* true iff file just opened */\ + FILE *file; /* output file */\ + long buffer_space; /* amount of space for clist buffer, */\ + /* 0 means not using clist */\ + byte *buf; /* buffer for rendering */\ + /* ---- Begin async rendering support --- */\ + gs_memory_t *buffer_memory; /* allocator for command list */\ + gs_memory_t *bandlist_memory; /* allocator for bandlist files */\ + proc_free_up_bandlist_memory((*free_up_bandlist_memory)); /* if nz, proc to free some bandlist memory */\ + gx_page_queue *page_queue; /* if <> 0,page queue for gdevprna NOT GC'd */\ + bool is_async_renderer; /* device is only the rendering part of async device */\ + gx_device_printer *async_renderer; /* in async writer, pointer to async renderer */\ + uint clist_disable_mask; /* mask of clist options to disable */\ + /* ---- End async rendering support --- */\ + gx_device_procs orig_procs /* original (std_)procs */ + +/* The device descriptor */ +struct gx_device_printer_s { + gx_device_common; + gx_prn_device_common; +}; + +/* 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); + +/* Default printer-specific procedures */ +prn_dev_proc_get_space_params(gdev_prn_default_get_space_params); +prn_dev_proc_start_render_thread(gx_default_start_render_thread); /* for async rendering only, see gdevprna.c */ +prn_dev_proc_open_render_device(gx_default_open_render_device); +prn_dev_proc_close_render_device(gx_default_close_render_device); +prn_dev_proc_buffer_page(gx_default_buffer_page); /* returns an error */ +prn_dev_proc_get_overlay_bits(gdev_prn_get_overlay_bits); +prn_dev_proc_locate_overlay_buffer(gdev_prn_locate_overlay_buffer); + +/* 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, */\ + NULL, /* get_clipping_box */\ + NULL, /* begin_typed_image */\ + NULL, /* map_color_rgb_alpha */\ + NULL, /* create_compositor */\ + NULL, /* get_hardware_params */\ + NULL /* text_begin */\ +} + +/* The standard printer device procedures */ +/* (using gdev_prn_open/output_page/close). */ +extern const 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,\ + gdev_prn_default_get_space_params,\ + gx_default_start_render_thread,\ + gx_default_open_render_device,\ + gx_default_close_render_device,\ + gx_default_buffer_page,\ + gdev_prn_get_overlay_bits,\ + gdev_prn_locate_overlay_buffer\ + },\ + { PRN_MAX_BITMAP, PRN_BUFFER_SPACE,\ + { band_params_initial_values },\ + 0/*false*/, /* params_are_read_only */\ + BandingAuto /* banding_type */\ + },\ + { 0 }, /* fname */\ + 0/*false*/, /* OpenOutputFile */\ + 0/*false*/, /* ReopenPerPage */\ + 0/*false*/, -1, /* Duplex[_set] */\ + 0/*false*/, 0, 0, 0, /* file_is_new ... buf */\ + 0, 0, 0, 0, 0/*false*/, 0, 0, /* buffer_memory ... clist_dis'_mask */\ + { 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,\ + gdev_prn_default_get_space_params,\ + gx_default_start_render_thread,\ + gx_default_open_render_device,\ + gx_default_close_render_device,\ + gx_default_buffer_page,\ + gdev_prn_get_overlay_bits,\ + gdev_prn_locate_overlay_buffer\ + },\ + { PRN_MAX_BITMAP, PRN_BUFFER_SPACE,\ + { band_params_initial_values },\ + 0/*false*/, /* params_are_read_only */\ + BandingAuto /* banding_type */\ + },\ + { 0 }, /* fname */\ + 0/*false*/, /* OpenOutputFile */\ + 0/*false*/, /* ReopenPerPage */\ + 0/*false*/, -1, /* Duplex[_set] */\ + 0/*false*/, 0, 0, 0, /* file_is_new ... buf */\ + 0, 0, 0, 0, 0/*false*/, 0, 0, /* buffer_memory ... clist_dis'_mask */\ + { 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_positionable(P3(gx_device *dev, bool binary_mode, + bool positionable)); +/* open_printer defaults positionable = false */ +int gdev_prn_open_printer(P2(gx_device * dev, bool 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 *)); + +/* The default print_page_copies procedure just calls print_page */ +/* the given number of times. */ +prn_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 *)); + +/* Allocate / reallocate / free printer memory. */ +int gdev_prn_allocate_memory(P4(gx_device *pdev, + gdev_prn_space_params *space, + int new_width, int new_height)); +int gdev_prn_reallocate_memory(P4(gx_device *pdev, + gdev_prn_space_params *space, + int new_width, int new_height)); +int gdev_prn_free_memory(P1(gx_device *pdev)); + +/* 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 *, 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/gdevprna.h b/pstoraster/gdevprna.h new file mode 100644 index 0000000000..799a8dc12d --- /dev/null +++ b/pstoraster/gdevprna.h @@ -0,0 +1,190 @@ +/* Copyright (C) 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Generic asynchronous printer driver support */ + +/* Initial version 2/1/1998 by John Desrosiers (soho@crl.com) */ +/* 7/28/98 ghost@aladdin.com - Updated to Ghostscript coding standards. */ + +#ifndef gdevprna_INCLUDED +# define gdevprna_INCLUDED + +# include "gdevprn.h" +# include "gxsync.h" + +/* + * General + * ------- + * Async drivers actually create two separate instances of the device at + * the same time. The first (the writer instance) is only used in the + * interpretation operation; it feeds rendering commands into the command + * lists. The second device instance is used only for rendering the + * commands placed into the command list by the writer. + + * The writer builds a command list for an entire page; the command list + * is only queued for rendering once a page's command list is completely + * built. The only exception to this rule is when the interpreter runs + * out of memory, or when no free command list memory is available. In + * such cases, the interpreter queues a "partial page" consisting of all + * command list data written so far, plus a command indicating that the + * page description is not complete. After queuing the partial page, the + * interpereter waits until the rendering process has freed enough + * command list memory to enable the interpreter to proceed. + + * To avoid deadlocks when the system runs out of memory, special + * memory allocation provisions are made on both the writer and + * renderer sides. On the writer side, enough "reserve" bandlist + * memory is set aside at startup time to cover the needs of queuing a + * partial page to the renderer. The renderer operates out of a fixed + * memory space; that way, it can always complete rendering pages with + * the memory it has. To this end, the writer protects the renderer + * from consuming unbounded amounts of memory by a) never putting + * complex paths into the command list, b) pre-clipping any output + * unless the clip path consists of a single rectangle, c) never putting + * high-level images into the clip path unless the image in question + * meets some very stringent requirements, such as only being rotated by + * even multiples of 90 degrees and having source-image data rows which + * fit into the command buffer in one piece. These restrictions are what + * dictate the "restricted bandlist format." + + * Note that the renderer's instance of the device driver uses the + * renderer's memory. That implies that it must also operate in a small, + * fixed amount of memory, and must do all memory allocation using the + * memory allocator pointed to by the render device's ->memory member. + + * Opening the Device + * ------------------ + * The writer instance is opened first. This occurs when the system + * calls the "standard" open procedure via the device's procedure + * vector. The driver must implement the open function, but must call + * down to gdev_prn_async_write_open instead of calling down to + * gdev_prn_open. Before calling down to gdev_prn_async_write_open, the + * driver must: + * a - init several procedure vectors, to wit: start_render_thread, + * buffer_page, print_page_copies, + * b - init space_params.band.BandWidth, space_params.band.BandHeight, + * space_params.BufferSpace (see extended comments in gdevasyn.c + * for details on computing appropriate values). + * c - if it implements those functions, the driver must init the + * procedure vectors for: put_params, get_hardware_params, + * output_page, open_render_device. + * Notice that there are two procedure vectors: the usual std_procs, and + * the printer-specific printer_procs. + + * Since partial page support imposes extra requirements on drivers, + * such support can be disabled by zeroing out (in the async writer open + * routine, after calling down to gdev_prn_async_write_open) the + * free_up_bandlist_memory member of the driver structure. Doing so + * will, of course, cause interpretation to fail if memory runs out. + + * Once the driver calls down to gdev_prn_async_write_open, the async + * support logic will create a second instance of the driver for + * rendering, but will not open it just yet. Instead, the async logic + * will attempt to synchronize the two device instances. + + * Synchrnonizing the instances + * ---------------------------- + * While still in the gdev_prn_async_write_open routine, the async logic + * will call printer_procs.start_render_thread (which the driver is + * required to implement). start_render_thread must somehow either start a new + * thread or rendez-vous with an existing thread for use in rendering, + * then return. start_render_thread must also have caused the render thread + * to call gdev_prn_async_render_thread, passing it as an argument a magic + * cookie passed to start_render_thread. start_render_thread will only + * return once the device has been closed and all renering has been + * completed. + + * The render device will be opened on the render device's thread, by + * calling printer_procs.open_render_device. + + * Rendering Operation + * ------------------- + * During rendering, the device will not see rendering operations -- the + * first "rendering" operations the driver will see is when the renderer + * instance's print_page_copies or buffer_page routines get called. In + * both cases, the appropriate routine must then perform get_bits calls + * on the async logic in order to retrieve rendered bits, then transmit + * them to the appropriate device buffers. + + * The complication that is introduced is that which is related to + * partial pages: A buffer_page call instructs the driver to grab the + * rendered bits, but to keep the rendered bits available for later + * instead of marking on media. This implies that a buffer_page call + * opens a context where subsequent buffer_page's and print_page_copies' + * must first initialize the rendering buffers with the previous + * rendering results before calling get_bits. Drivers use the + * locate_overlay_buffer function to initialize the driver's rendering + * buffers. The first print_page_copies closes the context that was + * opened by the initial buffer_page -- the driver must go back to + * normal rendering until a new buffer_page comes along. + */ + +/* -------------- Type declarations --------------- */ + +/* typedef is in gdevprn.h */ +/* typedef struct gdev_prn_start_render_params_s gdev_prn_start_render_params;*/ +struct gdev_prn_start_render_params_s { + gx_device_printer *writer_device;/* writer dev that points to render dev */ + gx_semaphore_t *open_semaphore; /* signal this once open_code is set */ + int open_code; /* RETURNS status of open of reader device */ +}; + +/* -------- Macros used to initialize render-specific structures ------ */ + +#define init_async_render_procs(xpdev, xstart_render_thread,\ + xbuffer_page, xprint_page_copies)\ + BEGIN\ + (xpdev)->printer_procs.start_render_thread = (xstart_render_thread);\ + (xpdev)->printer_procs.buffer_page = (xbuffer_page);\ + (xpdev)->printer_procs.print_page_copies = (xprint_page_copies);\ + END + +/* -------------- Global procedure declarations --------- */ + +/* Open this printer device in ASYNC (overlapped) mode. + * + * This routine is always called by the concrete device's xx_open routine + * in lieu of gdev_prn_open. + */ +int gdev_prn_async_write_open(P4(gx_device_printer *pdev, int max_raster, + int min_band_height, int max_src_image_row)); + +/* Open the render portion of a printer device in ASYNC (overlapped) mode. + * + * This routine is always called by concrete device's xx_open_render_device + * in lieu of gdev_prn_open. + */ +int gdev_prn_async_render_open(P1(gx_device_printer *prdev)); + +/* + * Must be called by async device driver implementation (see + * gdevprna.h under "Synchronizing the Instances"). This is the + * rendering loop, which requires its own thread for as long as + * the device is open. This proc only returns after the device is closed. + */ +int /* rets 0 ok, -ve error code */ +gdev_prn_async_render_thread(P1(gdev_prn_start_render_params *)); + +#endif /* gdevprna_INCLUDED */ diff --git a/pstoraster/gdevps.c b/pstoraster/gdevps.c new file mode 100644 index 0000000000..5f461193ad --- /dev/null +++ b/pstoraster/gdevps.c @@ -0,0 +1,1119 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* PostScript-writing driver */ +#include "math_.h" +#include "memory_.h" +#include "time_.h" +#include "gx.h" +#include "gserrors.h" +#include "gscdefs.h" +#include "gsmatrix.h" /* for gsiparam.h */ +#include "gsiparam.h" +#include "gsline.h" +#include "gsparam.h" +#include "gxdevice.h" +#include "gscspace.h" +#include "gxdcolor.h" +#include "gzpath.h" +#include "gdevpsdf.h" +#include "gdevpstr.h" +#include "strimpl.h" +#include "sa85x.h" + +/**************************************************************** + * Notes: + * ASCII85EncodePages should use ASCIIHexEncode if LanguageLevel < 2. + * Images are never compressed; in fact, none of the other + * Distiller parameters do anything. + ****************************************************************/ + +/* ---------------- Device definition ---------------- */ + +/* Device procedures */ +private dev_proc_open_device(psw_open); +private dev_proc_output_page(psw_output_page); +private dev_proc_close_device(psw_close); +private dev_proc_copy_mono(psw_copy_mono); +private dev_proc_copy_color(psw_copy_color); +private dev_proc_put_params(psw_put_params); +private dev_proc_get_params(psw_get_params); +private dev_proc_fill_path(psw_fill_path); +private dev_proc_stroke_path(psw_stroke_path); +private dev_proc_fill_mask(psw_fill_mask); +private dev_proc_begin_image(psw_begin_image); + +#define X_DPI 720 +#define Y_DPI 720 + +typedef struct psw_path_state_s { + int num_points; /* # of points since last non-lineto */ + bool move; /* true iff last non-lineto was moveto */ + gs_point dprev[2]; /* line deltas before previous point, */ + /* if num_points - move >= 2 */ +} psw_path_state_t; + +typedef struct psw_image_params_s { + gx_bitmap_id id; + ushort width, height; +} psw_image_params_t; + +typedef struct gx_device_pswrite_s { + gx_device_psdf_common; + /* Settable parameters */ +#define LanguageLevel_default 2.0 +#define psdf_version_default psdf_version_level2 + float LanguageLevel; + /* End of parameters */ + bool ProduceEPS; + bool first_page; + long bbox_position; + psdf_binary_writer image_writer; +#define image_stream image_writer.strm +#define image_cache_size 197 +#define image_cache_reprobe_step 121 + psw_image_params_t image_cache[image_cache_size]; + bool cache_toggle; + /* Temporary state while writing a path */ + psw_path_state_t path_state; +} gx_device_pswrite; + +gs_private_st_suffix_add1_final(st_device_pswrite, gx_device_pswrite, + "gx_device_pswrite", device_pswrite_enum_ptrs, device_pswrite_reloc_ptrs, + gx_device_finalize, st_device_psdf, image_stream); + +#define psw_procs\ + { psw_open,\ + gx_upright_get_initial_matrix,\ + NULL, /* sync_output */\ + psw_output_page,\ + psw_close,\ + gx_default_rgb_map_rgb_color,\ + gx_default_rgb_map_color_rgb,\ + gdev_vector_fill_rectangle,\ + NULL, /* tile_rectangle */\ + psw_copy_mono,\ + psw_copy_color,\ + NULL, /* draw_line */\ + NULL, /* get_bits */\ + psw_get_params,\ + psw_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 */\ + psw_fill_path,\ + psw_stroke_path,\ + psw_fill_mask,\ + gdev_vector_fill_trapezoid,\ + gdev_vector_fill_parallelogram,\ + gdev_vector_fill_triangle,\ + NULL /****** WRONG ******/, /* draw_thin_line */\ + psw_begin_image,\ + NULL, /* image_data */\ + NULL, /* end_image */\ + NULL, /* strip_tile_rectangle */\ + NULL/******psw_strip_copy_rop******/\ + } + +const gx_device_pswrite gs_pswrite_device = +{std_device_dci_type_body(gx_device_pswrite, 0, "pswrite", + &st_device_pswrite, + DEFAULT_WIDTH_10THS * X_DPI / 10, DEFAULT_HEIGHT_10THS * Y_DPI / 10, + X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256), + psw_procs, + psdf_initial_values(psdf_version_default, 1 /*true */ ), /* (ASCII85EncodePages) */ + LanguageLevel_default, /* LanguageLevel */ + 0 /*false *//* ProduceEPS */ +}; + +const gx_device_pswrite gs_epswrite_device = +{std_device_dci_type_body(gx_device_pswrite, 0, "epswrite", + &st_device_pswrite, + DEFAULT_WIDTH_10THS * X_DPI / 10, DEFAULT_HEIGHT_10THS * Y_DPI / 10, + X_DPI, Y_DPI, 3, 24, 255, 255, 256, 256), + psw_procs, + psdf_initial_values(psdf_version_default, 1 /*true */ ), /* (ASCII85EncodePages) */ + LanguageLevel_default, /* LanguageLevel */ + 1 /*true *//* ProduceEPS */ +}; + +/* Vector device implementation */ +private int + psw_beginpage(P1(gx_device_vector * vdev)), psw_setlinewidth(P2(gx_device_vector * vdev, floatp width)), + psw_setcolors(P2(gx_device_vector * vdev, const gx_drawing_color * pdc)), + psw_dorect(P6(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1, + gx_path_type_t type)), psw_beginpath(P2(gx_device_vector * vdev, gx_path_type_t type)), + psw_moveto(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, gx_path_type_t type)), psw_lineto(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, gx_path_type_t type)), + psw_curveto(P10(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x1, floatp y1, floatp x2, floatp y2, + floatp x3, floatp y3, gx_path_type_t type)), psw_closepath(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x_start, floatp y_start, gx_path_type_t type)), + psw_endpath(P2(gx_device_vector * vdev, gx_path_type_t type)); +private const gx_device_vector_procs psw_vector_procs = +{ + /* Page management */ + psw_beginpage, + /* Imager state */ + psw_setlinewidth, + psdf_setlinecap, + psdf_setlinejoin, + psdf_setmiterlimit, + psdf_setdash, + psdf_setflat, + psdf_setlogop, + /* Other state */ + psw_setcolors, /* fill & stroke colors are the same */ + psw_setcolors, + /* Paths */ + psdf_dopath, + psw_dorect, + psw_beginpath, + psw_moveto, + psw_lineto, + psw_curveto, + psw_closepath, + psw_endpath +}; + +/* ---------------- File header ---------------- */ + +private const char *const psw_ps_header[] = +{ + "%!PS-Adobe-3.0", + "%%Pages: (atend)", + 0 +}; + +private const char *const psw_eps_header[] = +{ + "%!PS-Adobe-3.0 EPSF-3.0", + 0 +}; + +private const char *const psw_header[] = +{ + "%%EndComments", + "%%BeginProlog", + 0 +}; + +private const char *const psw_prolog[] = +{ + "%%BeginResource: procset GS_pswrite_ProcSet", + "/GS_pswrite_ProcSet 40 dict dup begin", + "/!{bind def}bind def/#{load def}!", + /* rG - */ + /* G - */ + "/rG{3{3 -1 roll 255 div}repeat setrgbcolor}!/G{255 div setgray}!/K{0 G}!", + /* r6 - */ + /* r5 - */ + /* r3 - */ + "/r6{dup 3 -1 roll rG}!/r5{dup 3 1 roll rG}!/r3{dup rG}!", + "/w/setlinewidth #/J/setlinecap #", + "/j/setlinejoin #/M/setmiterlimit #/d/setdash #/i/setflat #", + "/m/moveto #/l/lineto #/c/rcurveto #/h{p closepath}!/H{P closepath}!", + /* lx - */ + /* ly - */ + /* v - */ + /* y - */ + "/lx{0 rlineto}!/ly{0 exch rlineto}!/v{0 0 6 2 roll c}!/y{2 copy c}!", + /* re - */ + "/re{4 -2 roll m exch dup lx exch ly neg lx h}!", + /* ^ <-a> <-y> */ + "/^{3 index neg 3 index neg}!", + /* ... P - */ + "/P{count 0 gt{count -2 roll moveto p}if}!", + /* ... p - */ + "/p{count 2 idiv{count -2 roll rlineto}repeat}!", +"/f{P fill}!/f*{P eofill}!/S{P stroke}!/q/gsave #/Q/grestore #/rf{re fill}!", + "/Y{initclip P clip newpath}!/Y*{initclip P eoclip newpath}!/rY{re Y}!", + /* | */ + "/|{exch string readstring pop exch 4 1 roll 3 packedarray cvx exch 1 index def exec}!", + /* (|) + */ + "/+{dup type/nametype eq{2 index 7 add -3 bitshift 2 index mul}if}!", + /* (|) $ */ + "/@/currentfile #/${+ @ |}!", + /* Ix */ + "/Ix{[1 0 0 1 11 -2 roll exch neg exch neg]exch}!", + /* , - */ + /* If - */ + /* I - */ +"/,{true exch Ix imagemask}!/If{false exch Ix imagemask}!/I{exch Ix image}!", + 0 +}; + +private const char *const psw_1_prolog[] = +{ + 0 +}; + +private const char *const psw_1_5_prolog[] = +{ + "/Ic{exch Ix false 3 colorimage}!", + 0 +}; + +private const char *const psw_2_prolog[] = +{ + /* F */ + "/F{<>/CCITTFaxDecode filter}!", + /* X */ + /* - @X */ + /* +F */ + /* +F */ + /* @F */ + /* @C */ + "/X{/ASCII85Decode filter}!/@X{@ X}!/+F{2 index 2 index F}!/@F{@ +F}!/@C{@X +F}!", + /* (|) $X */ + /* -F */ + /* (|) $F */ + /* (|) $C */ + "/$X{+ @X |}!/-F{4 index 4 index F}!/$F{+ @ -F |}!/$C{+ @X -F |}!", + 0 +}; + +private const char *const psw_end_prolog[] = +{ + "end def", + "%%EndResource", + "%%EndProlog", + 0 +}; + +private void +psw_put_lines(stream * s, const char *const lines[]) +{ + int i; + + for (i = 0; lines[i] != 0; ++i) + pprints1(s, "%s\n", lines[i]); +} + +/* ---------------- Utilities ---------------- */ + +/* Reset the image cache. */ +private void +image_cache_reset(gx_device_pswrite * pdev) +{ + int i; + + for (i = 0; i < image_cache_size; ++i) + pdev->image_cache[i].id = gx_no_bitmap_id; + pdev->cache_toggle = false; +} + +/* Look up or enter image parameters in the cache. */ +/* Return -1 if the key is not in the cache, or its index. */ +/* If id is gx_no_bitmap_id or enter is false, do not enter it. */ +private int +image_cache_lookup(gx_device_pswrite * pdev, gx_bitmap_id id, + int width, int height, bool enter) +{ + int i1, i2; + psw_image_params_t *pip1; + psw_image_params_t *pip2; + + if (id == gx_no_bitmap_id) + return -1; + i1 = id % image_cache_size; + pip1 = &pdev->image_cache[i1]; + if (pip1->id == id && pip1->width == width && pip1->height == height) { + return i1; + } + i2 = (i1 + image_cache_reprobe_step) % image_cache_size; + pip2 = &pdev->image_cache[i2]; + if (pip2->id == id && pip2->width == width && pip2->height == height) { + return i2; + } + if (enter) { + int i = ((pdev->cache_toggle = !pdev->cache_toggle) ? i2 : i1); + psw_image_params_t *pip = &pdev->image_cache[i]; + + pip->id = id, pip->width = width, pip->height = height; + return i; + } + return -1; +} + +/* Prepare the encoding stream for image data. */ +/* Return 1 if we are using ASCII85 encoding. */ +private int +psw_image_stream_setup(gx_device_pswrite * pdev) +{ + int code = + psdf_begin_binary((gx_device_psdf *) pdev, &pdev->image_writer); + + return + (code < 0 ? code : + pdev->image_stream->state->template == &s_A85E_template ? 1 : 0); +} + +/* Clean up after writing an image. */ +private void +psw_image_cleanup(gx_device_pswrite * pdev) +{ + if (pdev->image_stream != 0) { + psdf_end_binary(&pdev->image_writer); + pdev->image_stream = 0; + } +} + +/* Write data for an image. Assumes width > 0, height > 0. */ +/****** IGNORES data_x ******/ +private void +psw_put_bits(stream * s, const byte * data, int data_x_bit, uint raster, + uint width_bits, int height) +{ + int y; + + for (y = 0; y < height; ++y) + pwrite(s, data + (data_x_bit >> 3) + y * raster, + (width_bits + 7) >> 3); +} +private int +psw_image_write(gx_device_pswrite * pdev, const char *imagestr, + const byte * data, int data_x, uint raster, gx_bitmap_id id, + int x, int y, int width, int height, int depth) +{ + stream *s = gdev_vector_stream((gx_device_vector *) pdev); + uint width_bits = width * depth; + int data_x_bit = data_x * depth; + int index = image_cache_lookup(pdev, id, width_bits, height, false); + char str[40]; + int code, encode; + + if (index >= 0) { + sprintf(str, "%d%c", index / 26, index % 26 + 'A'); + pprintd2(s, "%d %d ", x, y); + pprints2(s, "%s %s\n", str, imagestr); + return 0; + } + pprintd4(s, "%d %d %d %d ", x, y, width, height); + encode = code = psw_image_stream_setup(pdev); + if (code < 0) + return code; + if (depth == 1 && width > 16) { + /* + * We should really look at the statistics of the image before + * committing to using G4 encoding.... + */ + code = psdf_CFE_binary(&pdev->image_writer, width, height, false); + if (code < 0) + return code; + encode += 2; + } + if (id == gx_no_bitmap_id || width_bits * (ulong) height > 8000) { + const char *const uncached[4] = + { + "@", "@X", "@F", "@C" + }; + + pprints2(s, "%s %s\n", uncached[encode], imagestr); + psw_put_bits(pdev->image_stream, data, data_x_bit, raster, + width_bits, height); + psw_image_cleanup(pdev); + spputc(s, '\n'); + } else { + const char *const cached[4] = + { + "$", "$X", "$F", "$C" + }; + + index = image_cache_lookup(pdev, id, width_bits, height, true); + sprintf(str, "/%d%c ", index / 26, index % 26 + 'A'); + pputs(s, str); + if (depth != 1) + pprintld1(s, "%ld ", ((width_bits + 7) >> 3) * (ulong) height); + pprints1(s, "%s\n", cached[encode]); + psw_put_bits(pdev->image_stream, data, data_x_bit, raster, + width_bits, height); + psw_image_cleanup(pdev); + pprints1(s, "\n%s\n", imagestr); + } + return 0; +} + +/* Print a matrix. */ +private void +psw_put_matrix(stream * s, const gs_matrix * pmat) +{ + pprintg6(s, "[%g %g %g %g %g %g]", + pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty); +} + +/* ---------------- Vector device implementation ---------------- */ + +#define pdev ((gx_device_pswrite *)vdev) + +private int +psw_beginpage(gx_device_vector * vdev) +{ + stream *s = vdev->strm; + long page = vdev->PageCount + 1; + + if (pdev->first_page) { + psw_put_lines(s, + (pdev->ProduceEPS ? psw_eps_header : psw_ps_header)); + if (ftell(vdev->file) < 0) { /* File is not seekable. */ + pdev->bbox_position = -1; + pputs(s, "%%BoundingBox: (atend)\n"); + pputs(s, "%%HiResBoundingBox: (atend)\n"); + } else { /* File is seekable, leave room to rewrite bbox. */ + pdev->bbox_position = stell(s); + pputs(s, "%...............................................................\n"); + pputs(s, "%...............................................................\n"); + } + pprints1(s, "%%%%Creator: %s ", gs_product); + pprintld1(s, "%ld ", (long)gs_revision); + pprints1(s, "(%s)\n", vdev->dname); + { + struct tm tms; + time_t t; + char date_str[25]; + + time(&t); + tms = *localtime(&t); + sprintf(date_str, "%d/%02d/%02d %02d:%02d:%02d", + tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, + tms.tm_hour, tms.tm_min, tms.tm_sec); + pprints1(s, "%%%%CreationDate: %s\n", date_str); + } + if (pdev->params.ASCII85EncodePages) + pputs(s, "%%DocumentData: Clean7Bit\n"); + if (pdev->LanguageLevel == 2.0) + pputs(s, "%%LanguageLevel: 2\n"); + else if (pdev->LanguageLevel == 1.5) + pputs(s, "%%Extensions: CMYK\n"); + psw_put_lines(s, psw_header); + psw_put_lines(s, psw_prolog); + if (pdev->LanguageLevel < 1.5) + psw_put_lines(s, psw_1_prolog); + else { + psw_put_lines(s, psw_1_5_prolog); + if (pdev->LanguageLevel > 1.5) + psw_put_lines(s, psw_2_prolog); + } + psw_put_lines(s, psw_end_prolog); + } + pprintld2(s, "%%%%Page: %ld %ld\n%%%%BeginPageSetup\n", page, page); + pprintg2(s, "/pagesave save def GS_pswrite_ProcSet begin %g %g scale\n%%%%EndPageSetup\n", + 72.0 / vdev->HWResolution[0], 72.0 / vdev->HWResolution[1]); + return 0; +} + +private int +psw_setlinewidth(gx_device_vector * vdev, floatp width) +{ /* + * The vector scale is 1, but we have to rescale the line width + * (which is given in device pixels) to account for the actual + * page scaling in effect. + */ + return psdf_setlinewidth(vdev, width * 72.0 / vdev->HWResolution[1]); +} + +private int +psw_setcolors(gx_device_vector * vdev, const gx_drawing_color * pdc) +{ + if (!gx_dc_is_pure(pdc)) + return_error(gs_error_rangecheck); + /* PostScript only keeps track of a single color. */ + vdev->fill_color = *pdc; + vdev->stroke_color = *pdc; + { + stream *s = gdev_vector_stream(vdev); + gx_color_index color = gx_dc_pure_color(pdc); + int r = color >> 16; + int g = (color >> 8) & 0xff; + int b = color & 0xff; + + if (r == g && g == b) { + if (r == 0) + pputs(s, "K\n"); + else + pprintd1(s, "%d G\n", r); + } else if (r == g) + pprintd2(s, "%d %d r6\n", b, r); + else if (g == b) + pprintd2(s, "%d %d r3\n", r, g); + else if (r == b) + pprintd2(s, "%d %d r5\n", g, b); + else + pprintd3(s, "%d %d %d rG\n", r, g, b); + } + return 0; +} + +/* Redefine dorect to recognize rectangle fills. */ +private int +psw_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1, + gx_path_type_t type) +{ + if ((type & ~gx_path_type_rule) != gx_path_type_fill) + return psdf_dorect(vdev, x0, y0, x1, y1, type); + pprintg4(gdev_vector_stream(vdev), "%g %g %g %g rf\n", + fixed2float(x0), fixed2float(y0), + fixed2float(x1 - x0), fixed2float(y1 - y0)); + return 0; +} + +/* + * We redefine path tracing to use a compact form for polygons; also, + * we only need to write coordinates with 2 decimals of precision, + * since this is 10 times more precise than any existing output device. + */ +#define round_coord(v) (floor((v) * 100 + 0.5) / 100.0) +private void +print_coord2(stream * s, floatp x, floatp y, const char *str) +{ + pprintg2(s, "%g %g ", round_coord(x), round_coord(y)); + if (str != 0) + pputs(s, str); +} +#undef round_coord + +private int +psw_beginpath(gx_device_vector * vdev, gx_path_type_t type) +{ + pdev->path_state.num_points = 0; + pdev->path_state.move = false; + return 0; +} + +private int +psw_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y, + gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + + if (pdev->path_state.num_points > 1) + pputs(s, (pdev->path_state.move ? "P\n" : "p\n")); + print_coord2(s, x, y, NULL); + pdev->path_state.num_points = 1; + pdev->path_state.move = true; + return 0; +} + +private int +psw_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y, + gx_path_type_t type) +{ + double dx = x - x0, dy = y - y0; + + /* + * Omit null lines when filling. + ****** MAYBE WRONG IF PATH CONSISTS ONLY OF NULL LINES. ****** + */ + if (dx != 0 || dy != 0) { + stream *s = gdev_vector_stream(vdev); + + if (pdev->path_state.num_points - pdev->path_state.move >= 2 && + dx == -pdev->path_state.dprev[1].x && + dy == -pdev->path_state.dprev[1].y + ) + pputs(s, "^ "); + else + print_coord2(s, dx, dy, NULL); + pdev->path_state.num_points++; + pdev->path_state.dprev[1] = pdev->path_state.dprev[0]; + pdev->path_state.dprev[0].x = dx; + pdev->path_state.dprev[0].y = dy; + } + return 0; +} + +private int +psw_curveto(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3, + gx_path_type_t type) +{ + stream *s = gdev_vector_stream(vdev); + double dx1 = x1 - x0, dy1 = y1 - y0; + double dx2 = x2 - x0, dy2 = y2 - y0; + double dx3 = x3 - x0, dy3 = y3 - y0; + + if (pdev->path_state.num_points > 0) + pputs(s, (pdev->path_state.move ? + (pdev->path_state.num_points == 1 ? "m\n" : "P\n") : + "p\n")); + if (dx1 == 0 && dy1 == 0) { + print_coord2(s, dx2, dy2, NULL); + print_coord2(s, dx3, dy3, "v\n"); + } else if (x3 == x2 && y3 == y2) { + print_coord2(s, dx1, dy1, NULL); + print_coord2(s, dx2, dy2, "y\n"); + } else { + print_coord2(s, dx1, dy1, NULL); + print_coord2(s, dx2, dy2, NULL); + print_coord2(s, dx3, dy3, "c\n"); + } + pdev->path_state.num_points = 0; + pdev->path_state.move = false; + return 0; +} + +private int +psw_closepath(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x_start, floatp y_start, gx_path_type_t type) +{ + pputs(gdev_vector_stream(vdev), + (pdev->path_state.num_points > 0 && pdev->path_state.move ? + "H\n" : "h\n")); + pdev->path_state.num_points = 0; + pdev->path_state.move = false; + return 0; +} + +private int +psw_endpath(gx_device_vector * vdev, gx_path_type_t type) +{ + stream *s = vdev->strm; + const char *star = (type & gx_path_type_even_odd ? "*" : ""); + + if (pdev->path_state.num_points > 1 && !pdev->path_state.move) + pputs(s, "p "); + if (type & gx_path_type_fill) { + if (type & (gx_path_type_stroke | gx_path_type_clip)) + pprints1(s, "q f%s Q ", star); + else + pprints1(s, "f%s\n", star); + } + if (type & gx_path_type_stroke) { + if (type & gx_path_type_clip) + pputs(s, "q S Q "); + else + pputs(s, "S\n"); + } + if (type & gx_path_type_clip) + pprints1(s, "Y%s\n", star); + return 0; +} + +#undef pdev + +/* ---------------- Driver procedures ---------------- */ + +#define vdev ((gx_device_vector *)dev) +#define pdev ((gx_device_pswrite *)dev) + +/* ------ Open/close/page ------ */ + +/* Open the device. */ +private int +psw_open(gx_device * dev) +{ + vdev->v_memory = dev->memory; +/****** WRONG ******/ + vdev->vec_procs = &psw_vector_procs; + { + int code = gdev_vector_open_file_bbox(vdev, 512, true); + + if (code < 0) + return code; + } + gdev_vector_init(vdev); + pdev->first_page = true; + pdev->binary_ok = !pdev->params.ASCII85EncodePages; + image_cache_reset(pdev); + return 0; +} + +/* Wrap up ("output") a page. */ +private int +psw_output_page(gx_device * dev, int num_copies, int flush) +{ + stream *s = gdev_vector_stream(vdev); + + if (num_copies != 1) + pprintd1(s, "userdict /#copies %d put\n", num_copies); + pprints1(s, "end %s pagesave restore\n%%%%PageTrailer\n", + (flush ? "showpage" : "copypage")); + sflush(s); + vdev->in_page = false; + pdev->first_page = false; + gdev_vector_reset(vdev); + image_cache_reset(pdev); + return 0; +} + +/* Close the device. */ +/* Note that if this is being called as a result of finalization, */ +/* the stream may no longer exist; but the file will still be open. */ +private int +psw_close(gx_device * dev) +{ + FILE *f = vdev->file; + + fprintf(f, "%%%%Trailer\n%%%%Pages: %ld\n", dev->PageCount); + { + gs_rect bbox; + long save_pos; + + gx_device_bbox_bbox(vdev->bbox_device, &bbox); + if (pdev->bbox_position >= 0) { + save_pos = ftell(f); + fseek(f, pdev->bbox_position, SEEK_SET); + } + fprintf(f, "%%%%BoundingBox: %d %d %d %d\n", + (int)floor(bbox.p.x), (int)floor(bbox.p.y), + (int)ceil(bbox.q.x), (int)ceil(bbox.q.y)); + fprintf(f, "%%%%HiResBoundingBox: %f %f %f %f\n", + bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y); + if (pdev->bbox_position >= 0) { + fputc('%', f); + fseek(f, save_pos, SEEK_SET); + } + } + if (!pdev->ProduceEPS) + fputs("%%EOF\n", f); + gdev_vector_close_file(vdev); + return 0; +} + +/* ---------------- Get/put parameters ---------------- */ + +/* Get parameters. */ +private int +psw_get_params(gx_device * dev, gs_param_list * plist) +{ + int code = gdev_psdf_get_params(dev, plist); + int ecode; + + if (code < 0) + return code; + if ((ecode = param_write_float(plist, "LanguageLevel", &pdev->LanguageLevel)) < 0) + return ecode; + return code; +} + +/* Put parameters. */ +private int +psw_put_params(gx_device * dev, gs_param_list * plist) +{ + int ecode = 0; + int code; + gs_param_name param_name; + float ll = pdev->LanguageLevel; + psdf_version save_version = pdev->version; + + switch (code = param_read_float(plist, (param_name = "LanguageLevel"), &ll)) { + case 0: + if (ll == 1.0 || ll == 1.5 || ll == 2.0) + break; + code = gs_error_rangecheck; + default: + ecode = code; + param_signal_error(plist, param_name, ecode); + case 1: + ; + } + + if (ecode < 0) + return ecode; + /* + * We have to set version to the new value, because the set of + * legal parameter values for psdf_put_params varies according to + * the version. + */ + { + static const psdf_version vv[3] = + { + psdf_version_level1, psdf_version_level1_color, + psdf_version_level2 + }; + + pdev->version = vv[(int)(ll * 2) - 2]; + } + code = gdev_psdf_put_params(dev, plist); + if (code < 0) { + pdev->version = save_version; + return code; + } + pdev->LanguageLevel = ll; + return code; +} + +/* ---------------- Images ---------------- */ + +/* Copy a monochrome bitmap. */ +private int +psw_copy_mono(gx_device * dev, const byte * data, + int data_x, int raster, gx_bitmap_id id, int x, int y, int w, int h, + gx_color_index zero, gx_color_index one) +{ + gx_drawing_color color; + const char *op; + int code = 0; + + if (w <= 0 || h <= 0) + return 0; + (*dev_proc(vdev->bbox_device, copy_mono)) + ((gx_device *) vdev->bbox_device, data, data_x, raster, id, + x, y, w, h, zero, one); + if (one == gx_no_color_index) { + color_set_pure(&color, zero); + code = gdev_vector_update_fill_color((gx_device_vector *) pdev, + &color); + op = "If"; + } else if (zero == vdev->black && one == vdev->white) + op = "1 I"; + else { + if (zero != gx_no_color_index) { + code = (*dev_proc(dev, fill_rectangle)) (dev, x, y, w, h, zero); + if (code < 0) + return code; + } + color_set_pure(&color, one); + code = gdev_vector_update_fill_color((gx_device_vector *) pdev, + &color); + op = ","; + } + if (code < 0) + return 0; + return psw_image_write(pdev, op, data, data_x, raster, id, + x, y, w, h, 1); +} + +/* Copy a color bitmap. */ +private int +psw_copy_color(gx_device * dev, + const byte * data, int data_x, int raster, gx_bitmap_id id, + int x, int y, int w, int h) +{ + int depth = dev->color_info.depth; + const byte *bits = data + data_x * 3; + char op[6]; + + if (w <= 0 || h <= 0) + return 0; + (*dev_proc(vdev->bbox_device, copy_color)) + ((gx_device *) vdev->bbox_device, data, data_x, raster, id, + x, y, w, h); + /* + * If this is a 1-pixel-high image, check for it being all the + * same color, and if so, fill it as a rectangle. + */ + if (h == 1 && !memcmp(bits, bits + 3, (w - 1) * 3)) { + return (*dev_proc(dev, fill_rectangle)) + (dev, x, y, w, h, (bits[0] << 16) + (bits[1] << 8) + bits[2]); + } + sprintf(op, "%d Ic", depth / 3); /* RGB */ + return psw_image_write(pdev, op, data, data_x, raster, id, + x, y, w, h, depth); +} + +/* Fill or stroke a path. */ +/* We redefine these to skip empty paths. */ +private int +psw_fill_path(gx_device * dev, const gs_imager_state * pis, + gx_path * ppath, const gx_fill_params * params, + const gx_device_color * pdevc, const gx_clip_path * pcpath) +{ + if (gx_path_is_void(ppath)) + return 0; + return gdev_vector_fill_path(dev, pis, ppath, params, pdevc, pcpath); +} +private int +psw_stroke_path(gx_device * dev, const gs_imager_state * pis, + gx_path * ppath, const gx_stroke_params * params, + const gx_device_color * pdevc, const gx_clip_path * pcpath) +{ + if (gx_path_is_void(ppath) && + (gx_path_is_null(ppath) || + gs_currentlinecap((const gs_state *)pis) != gs_cap_round) + ) + return 0; + return gdev_vector_stroke_path(dev, pis, ppath, params, pdevc, pcpath); +} + +/* Fill a mask. */ +private int +psw_fill_mask(gx_device * dev, + const byte * data, int data_x, 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) +{ + if (w <= 0 || h <= 0) + return 0; + if (depth > 1 || + gdev_vector_update_fill_color(vdev, pdcolor) < 0 || + gdev_vector_update_clip_path(vdev, pcpath) < 0 || + gdev_vector_update_log_op(vdev, lop) < 0 + ) + return gx_default_fill_mask(dev, data, data_x, raster, id, + x, y, w, h, pdcolor, depth, lop, pcpath); + (*dev_proc(vdev->bbox_device, fill_mask)) + ((gx_device *) vdev->bbox_device, data, data_x, raster, id, + x, y, w, h, pdcolor, depth, lop, pcpath); + return psw_image_write(pdev, ",", data, data_x, raster, id, + x, y, w, h, 1); +} + +/* ---------------- High-level images ---------------- */ + +private image_enum_proc_plane_data(psw_image_plane_data); +private image_enum_proc_end_image(psw_image_end_image); +private const gx_image_enum_procs_t psw_image_enum_procs = +{ + psw_image_plane_data, psw_image_end_image +}; + +/* Start processing an image. */ +private int +psw_begin_image(gx_device * dev, + const gs_imager_state * pis, const gs_image_t * pim, + gs_image_format_t format, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * mem, gx_image_enum_common_t ** pinfo) +{ + gdev_vector_image_enum_t *pie = + gs_alloc_struct(mem, gdev_vector_image_enum_t, + &st_vector_image_enum, "psw_begin_image"); + const gs_color_space *pcs = pim->ColorSpace; + gs_color_space_index index; + int num_components; + bool can_do = prect == 0; + int code; + + if (pie == 0) + return_error(gs_error_VMerror); + pie->memory = mem; + *pinfo = (gx_image_enum_common_t *) pie; + if (!pim->ImageMask) { + index = gs_color_space_get_index(pcs); + num_components = gs_color_space_num_components(pcs); + } + if (pdev->LanguageLevel < 2 && !pim->ImageMask) { /* + * Restrict ourselves to Level 1 images: device color spaces, [0 + * 1] decode, bits per component <= 8, no CombineWithColor. + */ + if (pim->BitsPerComponent > 8 || pim->CombineWithColor) + can_do = false; + else { + int i; + + switch (index) { + case gs_color_space_index_DeviceGray: + case gs_color_space_index_DeviceRGB: + case gs_color_space_index_DeviceCMYK: + for (i = 0; i < num_components * 2; ++i) + if (pim->Decode[i] != (i & 1)) + can_do = false; + break; + default: + can_do = false; + } + } + } + if (!can_do || + gdev_vector_begin_image(vdev, pis, pim, format, prect, pdcolor, + pcpath, mem, &psw_image_enum_procs, pie) < 0 || + (code = psw_image_stream_setup(pdev)) < 0 + ) + return gx_default_begin_image(dev, pis, pim, format, prect, + pdcolor, pcpath, mem, + &pie->default_info); + /* Write the image/colorimage/imagemask preamble. */ + { + stream *s = gdev_vector_stream((gx_device_vector *) pdev); + const char *source = (code ? "@X" : "@"); + gs_matrix imat; + + pputs(s, "q"); + (*dev_proc(dev, get_initial_matrix)) (dev, &imat); + gs_matrix_scale(&imat, 72.0 / dev->HWResolution[0], + 72.0 / dev->HWResolution[1], &imat); + gs_matrix_invert(&imat, &imat); + gs_matrix_multiply(&ctm_only(pis), &imat, &imat); + psw_put_matrix(s, &imat); + pprintd2(s, "concat\n%d %d ", pie->width, pie->height); + if (pim->ImageMask) { + pputs(s, (pim->Decode[0] == 0 ? "false" : "true")); + psw_put_matrix(s, &pim->ImageMatrix); + pprints1(s, "%s imagemask\n", source); + } else { + pprintd1(s, "%d", pim->BitsPerComponent); + psw_put_matrix(s, &pim->ImageMatrix); + if (index == gs_color_space_index_DeviceGray) + pprints1(s, "%s image\n", source); + else { + if (format == gs_image_format_chunky) + pprints1(s, "%s false", source); + else + pprints2(s, "%s %strue", source, + "dup dup dup " + (16 - num_components * 4)); + pprintd1(s, " %d colorimage\n", num_components); + } + } + } + return 0; +} + +/* Process the next piece of an image. */ +private int +psw_image_plane_data(gx_device * dev, + gx_image_enum_common_t * info, const gx_image_plane_t * planes, int height) +{ + gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info; + + if (pie->default_info) + return gx_image_plane_data(pie->default_info, planes, height); + gx_image_plane_data(pie->bbox_info, planes, height); + { + int pi; + + for (pi = 0; pi < pie->num_planes; ++pi) + psw_put_bits(pdev->image_stream, planes[pi].data, + planes[pi].data_x * info->plane_depths[pi], + planes[pi].raster, + pie->width * info->plane_depths[pi], + height); + } + return (pie->y += height) >= pie->height; +} + +/* Clean up by releasing the buffers. */ +private int +psw_image_end_image(gx_device * dev, gx_image_enum_common_t * info, + bool draw_last) +{ + gdev_vector_image_enum_t *pie = (gdev_vector_image_enum_t *) info; + int code; + + code = gdev_vector_end_image(vdev, pie, draw_last, pdev->white); + if (code > 0) { + psw_image_cleanup(pdev); + pputs(pdev->strm, "\nQ\n"); + } + return code; +} diff --git a/pstoraster/gdevpsde.c b/pstoraster/gdevpsde.c new file mode 100644 index 0000000000..9389b60ab2 --- /dev/null +++ b/pstoraster/gdevpsde.c @@ -0,0 +1,282 @@ +/* Copyright (C) 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Embedded font writing */ +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsccode.h" +#include "gsmatrix.h" +#include "gxfixed.h" +#include "gxfont.h" +#include "gxfont1.h" +#include "stream.h" +#include "gdevpstr.h" +#include "gdevpsdf.h" + +private int +embed_table(gs_param_list * plist, const char *key, const float *values, + int count) +{ + if (count != 0) { + gs_param_float_array fa; + + fa.size = count; + fa.data = values; + return param_write_float_array(plist, key, &fa); + } + return 0; +} + +private void +embed_uid(stream * s, const gs_uid * puid) +{ + if (uid_is_UniqueID(puid)) + pprintld1(s, "/UniqueID %ld def\n", puid->id); + else if (uid_is_XUID(puid)) { + uint i, n = uid_XUID_size(puid); + + pputs(s, "/XUID ["); + for (i = 0; i < n; ++i) + pprintld1(s, "%ld ", uid_XUID_values(puid)[i]); + pputs(s, "] def\n"); + } +} + +/* Write an embedded Type 1 font. */ +int +psdf_embed_type1_font(stream * s, gs_font_type1 * pfont) +{ + const gs_type1_data *const pdata = &pfont->data; + gs_param_list *plist; + param_printer_params_t ppp; + int code; + + ppp = param_printer_params_default; + ppp.item_suffix = " def\n"; + code = psdf_alloc_param_printer(&plist, &ppp, s, + print_binary_ok, s->memory); + if (code < 0) + return 0; + + /* Write the font header. */ + + pputs(s, "%!PS-AdobeFont-1.0: "); + pwrite(s, pfont->font_name.chars, pfont->font_name.size); + pputs(s, "\n11 dict begin\n"); + + /* Write FontInfo. Currently we don't write anything there. */ + + pputs(s, "/FontInfo 1 dict dup begin\n"); + pputs(s, "end readonly def\n"); + + /* Write the main font dictionary. */ + + pputs(s, "/FontName /"); + pwrite(s, pfont->font_name.chars, pfont->font_name.size); + pputs(s, " def\n"); + pputs(s, "/Encoding "); + switch (pfont->encoding_index) { + case 0: + pputs(s, "StandardEncoding"); + break; + case 1: + pputs(s, "ISOLatin1Encoding"); + break; + default:{ + gs_char i; + + pputs(s, "256 array\n"); + pputs(s, "0 1 255 {1 index exch /.notdef put} for\n"); + for (i = 0; i < 256; ++i) { + gs_glyph glyph = + (*pfont->procs.encode_char) (NULL, (gs_font *) pfont, &i); + const char *namestr; + uint namelen; + + if (glyph != gs_no_glyph && + (namestr = (*pfont->procs.callbacks.glyph_name) (glyph, &namelen)) != 0 && + !(namelen == 7 && !memcmp(namestr, ".notdef", 7)) + ) { + pprintd1(s, "dup %d /", (int)i); + pwrite(s, namestr, namelen); + pputs(s, " put\n"); + } + } + pputs(s, "readonly"); + } + } + pputs(s, " def\n"); + pprintg6(s, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", + pfont->FontMatrix.xx, pfont->FontMatrix.xy, + pfont->FontMatrix.yx, pfont->FontMatrix.yy, + pfont->FontMatrix.tx, pfont->FontMatrix.ty); + embed_uid(s, &pfont->UID); + pprintg4(s, "/FontBBox {%g %g %g %g} readonly def\n", + pfont->FontBBox.p.x, pfont->FontBBox.p.y, + pfont->FontBBox.q.x, pfont->FontBBox.q.y); + { + private const gs_param_item_t font_items[] = + { + {"FontType", gs_param_type_int, + offset_of(gs_font_type1, FontType)}, + {"PaintType", gs_param_type_int, + offset_of(gs_font_type1, PaintType)}, + {"StrokeWidth", gs_param_type_float, + offset_of(gs_font_type1, StrokeWidth)}, + gs_param_item_end + }; + + code = gs_param_write_items(plist, pfont, NULL, font_items); + if (code < 0) + return code; + } + pputs(s, "currentdict end\n"); + + /* Write the Private dictionary. */ + + pputs(s, "dup /Private 17 dict dup begin\n"); + pputs(s, "/-|{string currentfile exch readstring pop}executeonly def\n"); + pputs(s, "/|-{noaccess def}executeonly def\n"); + pputs(s, "/|{noaccess put}executeonly def\n"); + { + private const gs_param_item_t private_items[] = + { + {"lenIV", gs_param_type_int, + offset_of(gs_type1_data, lenIV)}, + {"BlueFuzz", gs_param_type_int, + offset_of(gs_type1_data, BlueFuzz)}, + {"BlueScale", gs_param_type_float, + offset_of(gs_type1_data, BlueScale)}, + {"BlueShift", gs_param_type_float, + offset_of(gs_type1_data, BlueShift)}, + {"ExpansionFactor", gs_param_type_float, + offset_of(gs_type1_data, ExpansionFactor)}, + {"ForceBold", gs_param_type_bool, + offset_of(gs_type1_data, ForceBold)}, + {"LanguageGroup", gs_param_type_int, + offset_of(gs_type1_data, LanguageGroup)}, + {"RndStemUp", gs_param_type_bool, + offset_of(gs_type1_data, RndStemUp)}, + gs_param_item_end + }; + gs_type1_data defaults; + + defaults.lenIV = 4; + defaults.BlueFuzz = 1; + defaults.BlueScale = 0.039625; + defaults.BlueShift = 7.0; + defaults.ExpansionFactor = 0.06; + defaults.ForceBold = false; + defaults.LanguageGroup = 0; + defaults.RndStemUp = true; + code = gs_param_write_items(plist, pdata, &defaults, private_items); + if (code < 0) + return code; + embed_table(plist, "BlueValues", pdata->BlueValues.values, + pdata->BlueValues.count); + embed_table(plist, "OtherBlues", pdata->OtherBlues.values, + pdata->OtherBlues.count); + embed_table(plist, "FamilyBlues", pdata->FamilyBlues.values, + pdata->FamilyBlues.count); + embed_table(plist, "FamilyOtherBlues", pdata->FamilyOtherBlues.values, + pdata->FamilyOtherBlues.count); + embed_table(plist, "StdHW", pdata->StdHW.values, + pdata->StdHW.count); + embed_table(plist, "StemSnapH", pdata->StemSnapH.values, + pdata->StemSnapH.count); + embed_table(plist, "StemSnapV", pdata->StemSnapV.values, + pdata->StemSnapV.count); + } + embed_uid(s, &pfont->UID); + pputs(s, "/MinFeature{16 16} |-\n"); + pputs(s, "/password 5839 def\n"); + + /* Write the Subrs. */ + + { + int n, i; + gs_const_string str; + + for (n = 0; + (*pdata->procs->subr_data) (pfont, n, false, &str) != + gs_error_rangecheck; + ) + ++n; + pprintd1(s, "/Subrs %d array\n", n); + for (i = 0; i < n; ++i) + if ((*pdata->procs->subr_data) (pfont, i, false, &str) >= 0) { + char buf[50]; + + sprintf(buf, "dup %d %u -| ", i, str.size); + pputs(s, buf); + pwrite(s, str.data, str.size); + pputs(s, " |\n"); + } + pputs(s, "|-\n"); + } + + /* We don't write OtherSubrs -- there had better not be any! */ + + /* Write the CharStrings. */ + + { + int num_chars = 0; + gs_glyph glyph; + int index = 0; + gs_const_string gdata; + int code; + + for (glyph = gs_no_glyph, index = 0; + code = (*pdata->procs->next_glyph) (pfont, &index, &glyph), + index != 0; + ) + if (code == 0 && (*pdata->procs->glyph_data) (pfont, glyph, &gdata) >= 0) + ++num_chars; + pprintd1(s, "2 index /CharStrings %d dict dup begin\n", num_chars); + for (glyph = gs_no_glyph, index = 0; + code = (*pdata->procs->next_glyph) (pfont, &index, &glyph), + index != 0; + ) + if (code == 0 && (*pdata->procs->glyph_data) (pfont, glyph, &gdata) >= 0) { + uint gssize; + const char *gstr = + (*pfont->procs.callbacks.glyph_name) (glyph, &gssize); + + pputs(s, "/"); + pwrite(s, gstr, gssize); + pprintd1(s, " %d -| ", gdata.size); + pwrite(s, gdata.data, gdata.size); + pputs(s, " |-\n"); + } + } + + /* Wrap up. */ + + pputs(s, "end\nend\nreadonly put\nnoaccess put\n"); + pputs(s, "dup/FontName get exch definefont pop\n"); + psdf_free_param_printer(plist); + return 0; +} diff --git a/pstoraster/gdevpsdf.c b/pstoraster/gdevpsdf.c new file mode 100644 index 0000000000..38e5f40983 --- /dev/null +++ b/pstoraster/gdevpsdf.c @@ -0,0 +1,514 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Common utilities for PostScript and PDF writers */ +#include "string_.h" +#include "gx.h" +#include "gserrors.h" +#include "gdevpsdf.h" +#include "gdevpstr.h" +#include "scanchar.h" +#include "strimpl.h" +#include "sa85x.h" +#include "scfx.h" +#include "sstring.h" + +/* Structure descriptor */ +public_st_device_psdf(); + +/* ---------------- Vector implementation procedures ---------------- */ + +int +psdf_setlinewidth(gx_device_vector * vdev, floatp width) +{ + pprintg1(gdev_vector_stream(vdev), "%g w\n", width); + return 0; +} + +int +psdf_setlinecap(gx_device_vector * vdev, gs_line_cap cap) +{ + pprintd1(gdev_vector_stream(vdev), "%d J\n", cap); + return 0; +} + +int +psdf_setlinejoin(gx_device_vector * vdev, gs_line_join join) +{ + pprintd1(gdev_vector_stream(vdev), "%d j\n", join); + return 0; +} + +int +psdf_setmiterlimit(gx_device_vector * vdev, floatp limit) +{ + pprintg1(gdev_vector_stream(vdev), "%g M\n", limit); + return 0; +} + +int +psdf_setdash(gx_device_vector * vdev, const float *pattern, uint count, + floatp offset) +{ + stream *s = gdev_vector_stream(vdev); + int i; + + pputs(s, "[ "); + for (i = 0; i < count; ++i) + pprintg1(s, "%g ", pattern[i]); + pprintg1(s, "] %g d\n", offset); + return 0; +} + +int +psdf_setflat(gx_device_vector * vdev, floatp flatness) +{ + pprintg1(gdev_vector_stream(vdev), "%g i\n", flatness); + return 0; +} + +int +psdf_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop, + gs_logical_operation_t diff) +{ +/****** SHOULD AT LEAST DETECT SET-0 & SET-1 ******/ + return 0; +} + +int +psdf_setfillcolor(gx_device_vector * vdev, const gx_drawing_color * pdc) +{ + return psdf_set_color(vdev, pdc, "rg"); +} + +int +psdf_setstrokecolor(gx_device_vector * vdev, const gx_drawing_color * pdc) +{ + return psdf_set_color(vdev, pdc, "RG"); +} + +int +psdf_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1, + gx_path_type_t type) +{ + int code = (*vdev_proc(vdev, beginpath)) (vdev, type); + + if (code < 0) + return code; + pprintg4(gdev_vector_stream(vdev), "%g %g %g %g re\n", + fixed2float(x0), fixed2float(y0), + fixed2float(x1 - x0), fixed2float(y1 - y0)); + return (*vdev_proc(vdev, endpath)) (vdev, type); +} + +int +psdf_beginpath(gx_device_vector * vdev, gx_path_type_t type) +{ + return 0; +} + +int +psdf_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y, + bool first, gx_path_type_t type) +{ + pprintg2(gdev_vector_stream(vdev), "%g %g m\n", x, y); + return 0; +} + +int +psdf_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y, + gx_path_type_t type) +{ + pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x, y); + return 0; +} + +int +psdf_curveto(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3, + gx_path_type_t type) +{ + if (x1 == x0 && y1 == y0) + pprintg4(gdev_vector_stream(vdev), "%g %g %g %g v\n", + x2, y2, x3, y3); + else if (x3 == x2 && y3 == y2) + pprintg4(gdev_vector_stream(vdev), "%g %g %g %g y\n", + x1, y1, x2, y2); + else + pprintg6(gdev_vector_stream(vdev), "%g %g %g %g %g %g c\n", + x1, y1, x2, y2, x3, y3); + return 0; +} + +int +psdf_closepath(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x_start, floatp y_start, gx_path_type_t type) +{ + pputs(gdev_vector_stream(vdev), "h\n"); + return 0; +} + +/* endpath is deliberately omitted. */ + +/* ---------------- Utilities ---------------- */ + +int +psdf_set_color(gx_device_vector * vdev, const gx_drawing_color * pdc, + const char *rgs) +{ + if (!gx_dc_is_pure(pdc)) + return_error(gs_error_rangecheck); + { + stream *s = gdev_vector_stream(vdev); + gx_color_index color = gx_dc_pure_color(pdc); + float r = (color >> 16) / 255.0; + float g = ((color >> 8) & 0xff) / 255.0; + float b = (color & 0xff) / 255.0; + + if (r == g && g == b) + pprintg1(s, "%g", r), pprints1(s, " %s\n", rgs + 1); + else + pprintg3(s, "%g %g %g", r, g, b), pprints1(s, " %s\n", rgs); + } + return 0; +} + +/* ---------------- Binary data writing ---------------- */ + +/* Begin writing binary data. */ +int +psdf_begin_binary(gx_device_psdf * pdev, psdf_binary_writer * pbw) +{ + pbw->strm = pdev->strm; + pbw->dev = pdev; + /* If not binary, set up the encoding stream. */ + if (!pdev->binary_ok) + psdf_encode_binary(pbw, &s_A85E_template, NULL); + return 0; +} + +/* Add an encoding filter. The client must have allocated the stream state, */ +/* if any, using pdev->v_memory. */ +int +psdf_encode_binary(psdf_binary_writer * pbw, const stream_template * template, + stream_state * ss) +{ + gx_device_psdf *pdev = pbw->dev; + gs_memory_t *mem = pdev->v_memory; + stream *es = s_alloc(mem, "psdf_encode_binary(stream)"); + stream_state *ess = (ss == 0 ? (stream_state *) es : ss); + uint bsize = max(template->min_out_size, 256); /* arbitrary */ + byte *buf = gs_alloc_bytes(mem, bsize, "psdf_encode_binary(buf)"); + + if (es == 0 || buf == 0) { + gs_free_object(mem, buf, "psdf_encode_binary(buf)"); + gs_free_object(mem, es, "psdf_encode_binary(stream)"); + return_error(gs_error_VMerror); + } + if (ess == 0) + ess = (stream_state *) es; + s_std_init(es, buf, bsize, &s_filter_write_procs, s_mode_write); + ess->template = template; + ess->memory = mem; + es->procs.process = template->process; + es->memory = mem; + es->state = ess; + if (template->init) + (*template->init) (ess); + es->strm = pbw->strm; + pbw->strm = es; + return 0; +} + +/* Add a 2-D CCITTFax encoding filter. */ +int +psdf_CFE_binary(psdf_binary_writer * pbw, int w, int h, bool invert) +{ + gx_device_psdf *pdev = pbw->dev; + gs_memory_t *mem = pdev->v_memory; + const stream_template *template = &s_CFE_template; + stream_CFE_state *st = + gs_alloc_struct(mem, stream_CFE_state, template->stype, + "psdf_CFE_binary"); + int code; + + if (st == 0) + return_error(gs_error_VMerror); + (*template->set_defaults) ((stream_state *) st); + st->K = -1; + st->Columns = w; + st->Rows = h; + st->BlackIs1 = !invert; + code = psdf_encode_binary(pbw, template, (stream_state *) st); + if (code < 0) + gs_free_object(mem, st, "psdf_CFE_binary"); + return code; +} + +/* Finish writing binary data. */ +int +psdf_end_binary(psdf_binary_writer * pbw) +{ + gx_device_psdf *pdev = pbw->dev; + + /* Close the filters in reverse order. */ + /* Stop before we try to close the file stream. */ + while (pbw->strm != pdev->strm) { + stream *next = pbw->strm->strm; + + sclose(pbw->strm); + pbw->strm = next; + } + return 0; +} + +/* + * Write a string in its shortest form ( () or <> ). Note that + * this form is different depending on whether binary data are allowed. + * Currently we don't support ASCII85 strings ( <~ ~> ). + */ +void +psdf_write_string(stream * s, const byte * str, uint size, int print_ok) +{ + uint added = 0; + uint i; + const stream_template *template; + stream_AXE_state state; + stream_state *st = NULL; + + if (print_ok & print_binary_ok) { /* Only need to escape (, ), \, CR, EOL. */ + pputc(s, '('); + for (i = 0; i < size; ++i) { + byte ch = str[i]; + + switch (ch) { + case char_CR: + pputs(s, "\\r"); + continue; + case char_EOL: + pputs(s, "\\n"); + continue; + case '(': + case ')': + case '\\': + pputc(s, '\\'); + } + pputc(s, ch); + } + pputc(s, ')'); + return; + } + for (i = 0; i < size; ++i) { + byte ch = str[i]; + + if (ch == 0 || ch >= 127) + added += 3; + else if (strchr("()\\\n\r\t\b\f", ch) != 0) + ++added; + else if (ch < 32) + added += 3; + } + + if (added < size) { /* More efficient to represent as PostScript string. */ + template = &s_PSSE_template; + pputc(s, '('); + } else { /* More efficient to represent as hex string. */ + template = &s_AXE_template; + st = (stream_state *) & state; + s_AXE_init_inline(&state); + pputc(s, '<'); + } + + { + byte buf[100]; /* size is arbitrary */ + stream_cursor_read r; + stream_cursor_write w; + int status; + + r.ptr = str - 1; + r.limit = r.ptr + size; + w.limit = buf + sizeof(buf) - 1; + do { + w.ptr = buf - 1; + status = (*template->process) (st, &r, &w, true); + pwrite(s, buf, (uint) (w.ptr + 1 - buf)); + } + while (status == 1); + } +} + +/* Set up a write stream that just keeps track of the position. */ +int +psdf_alloc_position_stream(stream ** ps, gs_memory_t * mem) +{ + stream *s = *ps = s_alloc(mem, "psdf_alloc_position_stream"); + + if (s == 0) + return_error(gs_error_VMerror); + swrite_position_only(s); + return 0; +} + +/* ---------------- Parameter printing ---------------- */ + +typedef struct printer_param_list_s { + gs_param_list_common; + stream *strm; + param_printer_params_t params; + int print_ok; + bool any; +} printer_param_list_t; + +gs_private_st_ptrs1(st_printer_param_list, printer_param_list_t, + "printer_param_list_t", printer_plist_enum_ptrs, printer_plist_reloc_ptrs, + strm); +const param_printer_params_t param_printer_params_default = +{ + param_printer_params_default_values +}; + +/* We'll implement the other printers later if we have to. */ +private param_proc_xmit_typed(param_print_typed); +/*private param_proc_begin_xmit_collection(param_print_begin_collection); */ +/*private param_proc_end_xmit_collection(param_print_end_collection); */ +private const gs_param_list_procs printer_param_list_procs = { + param_print_typed, + NULL /* begin_collection */ , + NULL /* end_collection */ , + NULL /* get_next_key */ , + gs_param_request_default, + gs_param_requested_default +}; + +int +psdf_alloc_param_printer(gs_param_list ** pplist, + const param_printer_params_t * ppp, stream * s, + int print_ok, gs_memory_t * mem) +{ + printer_param_list_t *prlist = + gs_alloc_struct(mem, printer_param_list_t, &st_printer_param_list, + "psdf_alloc_param_printer"); + + *pplist = (gs_param_list *) prlist; + if (prlist == 0) + return_error(gs_error_VMerror); + prlist->procs = &printer_param_list_procs; + prlist->memory = mem; + prlist->strm = s; + prlist->params = *ppp; + prlist->print_ok = print_ok; + prlist->any = false; + return 0; +} + +void +psdf_free_param_printer(gs_param_list * plist) +{ + if (plist) { + printer_param_list_t *prlist = (printer_param_list_t *) plist; + + if (prlist->any && prlist->params.suffix) + pputs(prlist->strm, prlist->params.suffix); + gs_free_object(prlist->memory, plist, "psdf_free_param_printer"); + } +} + +#define prlist ((printer_param_list_t *)plist) +private int +param_print_typed(gs_param_list * plist, gs_param_name pkey, + gs_param_typed_value * pvalue) +{ + stream *s = prlist->strm; + + if (!prlist->any) { + if (prlist->params.prefix) + pputs(s, prlist->params.prefix); + prlist->any = true; + } + if (prlist->params.item_prefix) + pputs(s, prlist->params.item_prefix); + pprints1(s, "/%s", pkey); + switch (pvalue->type) { + case gs_param_type_null: + pputs(s, " null"); + break; + case gs_param_type_bool: + pputs(s, (pvalue->value.b ? " true" : " false")); + break; + case gs_param_type_int: + pprintd1(s, " %d", pvalue->value.i); + break; + case gs_param_type_long: + pprintld1(s, " %l", pvalue->value.l); + break; + case gs_param_type_float: + pprintg1(s, " %g", pvalue->value.f); + break; + case gs_param_type_string: + psdf_write_string(s, pvalue->value.s.data, pvalue->value.s.size, + prlist->print_ok); + break; + case gs_param_type_name: +/****** SHOULD USE #-ESCAPES FOR PDF ******/ + pputc(s, '/'); + pwrite(s, pvalue->value.n.data, pvalue->value.n.size); + break; + case gs_param_type_int_array: + { + uint i; + char sepr = (pvalue->value.ia.size <= 10 ? ' ' : '\n'); + + pputc(s, '['); + for (i = 0; i < pvalue->value.ia.size; ++i) { + pprintd1(s, "%d", pvalue->value.ia.data[i]); + pputc(s, sepr); + } + pputc(s, ']'); + } + break; + case gs_param_type_float_array: + { + uint i; + char sepr = (pvalue->value.fa.size <= 10 ? ' ' : '\n'); + + pputc(s, '['); + for (i = 0; i < pvalue->value.fa.size; ++i) { + pprintg1(s, "%g", pvalue->value.fa.data[i]); + pputc(s, sepr); + } + pputc(s, ']'); + } + break; + /*case gs_param_type_string_array: */ + /*case gs_param_type_name_array: */ + default: + return_error(gs_error_typecheck); + } + if (prlist->params.item_suffix) + pputs(s, prlist->params.item_suffix); + return 0; +} + +#undef prlist diff --git a/pstoraster/gdevpsdf.h b/pstoraster/gdevpsdf.h new file mode 100644 index 0000000000..1e814a52ff --- /dev/null +++ b/pstoraster/gdevpsdf.h @@ -0,0 +1,292 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Common output syntax and parameters for PostScript and PDF writers */ + +#ifndef gdevpsdf_INCLUDED +# define gdevpsdf_INCLUDED + +#include "gdevvec.h" +#include "gsparam.h" +#include "strimpl.h" +#include "scfx.h" + +/* ---------------- Distiller parameters ---------------- */ + +/* Parameters for controlling distillation of images. */ +typedef struct psdf_image_params_s { + stream_state *ACSDict; /* JPEG */ + bool AntiAlias; + bool AutoFilter; + int Depth; + stream_state *Dict; /* JPEG or CCITTFax */ + bool Downsample; + enum psdf_downsample_type { + ds_Average, + ds_Subsample + } DownsampleType; + bool Encode; + const char *Filter; + int Resolution; + const stream_template *filter_template; +} psdf_image_params; + +#define psdf_image_param_defaults(af, res, f, ft)\ + NULL/*ACSDict*/, 0/*false*/, af, -1, NULL/*Dict*/, 0/*false*/,\ + ds_Subsample, 1/*true*/, f, res, ft + +/* Declare templates for default image compression filters. */ +extern const stream_template s_CFE_template; + +/* Complete distiller parameters. */ +typedef struct psdf_distiller_params_s { + + /* General parameters */ + + bool ASCII85EncodePages; + enum psdf_auto_rotate_pages { + arp_None, + arp_All, + arp_PageByPage + } AutoRotatePages; + bool CompressPages; + long ImageMemory; + bool LZWEncodePages; + bool PreserveHalftoneInfo; + bool PreserveOPIComments; + bool PreserveOverprintSettings; + enum psdf_transfer_function_info { + tfi_Preserve, + tfi_Apply, + tfi_Remove + } TransferFunctionInfo; + enum psdf_ucr_and_bg_info { + ucrbg_Preserve, + ucrbg_Remove + } UCRandBGInfo; + bool UseFlateCompression; +#define psdf_general_param_defaults(ascii)\ + ascii, arp_None, 1/*true*/, 250000, 0/*false*/,\ + 0/*false*/, 0/*false*/, 0/*false*/, tfi_Apply, ucrbg_Remove, 1 /*true */ + + /* Color sampled image parameters */ + + psdf_image_params ColorImage; + enum psdf_color_conversion_strategy { + ccs_LeaveColorUnchanged, + ccs_UseDeviceDependentColor, + ccs_UseDeviceIndependentColor + } ColorConversionStrategy; + bool ConvertCMYKImagesToRGB; + bool ConvertImagesToIndexed; +#define psdf_color_image_param_defaults\ + { psdf_image_param_defaults(1/*true*/, 72, 0, 0) },\ + ccs_LeaveColorUnchanged, 1/*true*/, 0 /*false */ + + /* Grayscale sampled image parameters */ + + psdf_image_params GrayImage; +#define psdf_gray_image_param_defaults\ + { psdf_image_param_defaults(1/*true*/, 72, 0, 0) } + + /* Monochrome sampled image parameters */ + + psdf_image_params MonoImage; +#define psdf_mono_image_param_defaults\ + { psdf_image_param_defaults(0/*false*/, 300, "CCITTFaxEncode", &s_CFE_template) } + + /* Font embedding parameters */ + + gs_param_string_array AlwaysEmbed; + gs_param_string_array NeverEmbed; + bool EmbedAllFonts; + bool SubsetFonts; + int MaxSubsetPct; +#define psdf_font_param_defaults\ + { 0, 0, 1/*true*/ }, { 0, 0, 1/*true*/ },\ + 1/*true*/, 1/*true*/, 20 + +} psdf_distiller_params; + +/* Define PostScript/PDF versions, corresponding roughly to Adobe versions. */ +typedef enum { + psdf_version_level1 = 1000, /* Red Book Level 1 */ + psdf_version_level1_color = 1100, /* Level 1 + colorimage + CMYK color */ + psdf_version_level2 = 2000, /* Red Book Level 2 */ + psdf_version_level2_plus = 2017, /* Adobe release 2017 */ + psdf_version_ll3 = 3010 /* LanguageLevel 3, release 3010 */ +} psdf_version; + +/* Define the extended device structure. */ +#define gx_device_psdf_common\ + gx_device_vector_common;\ + psdf_version version;\ + bool binary_ok; /* derived from ASCII85EncodePages */\ + psdf_distiller_params params +typedef struct gx_device_psdf_s { + gx_device_psdf_common; +} gx_device_psdf; + +#define psdf_initial_values(version, ascii)\ + vector_initial_values,\ + version,\ + !(ascii),\ + { psdf_general_param_defaults(ascii),\ + psdf_color_image_param_defaults,\ + psdf_gray_image_param_defaults,\ + psdf_mono_image_param_defaults,\ + psdf_font_param_defaults\ + } + +/* st_device_psdf is never instantiated per se, but we still need to */ +/* extern its descriptor for the sake of subclasses. */ +extern_st(st_device_psdf); +#define public_st_device_psdf() /* in gdevpsdf.c */\ + gs_public_st_suffix_add0_final(st_device_psdf, gx_device_psdf,\ + "gx_device_psdf", device_psdf_enum_ptrs,\ + device_psdf_reloc_ptrs, gx_device_finalize, st_device_vector) +#define st_device_psdf_max_ptrs (st_device_vector_max_ptrs) + +/* Get/put parameters. */ +dev_proc_get_params(gdev_psdf_get_params); +dev_proc_put_params(gdev_psdf_put_params); + +/* Put a Boolean or integer parameter. */ +int psdf_put_bool_param(P4(gs_param_list * plist, gs_param_name param_name, + bool * pval, int ecode)); +int psdf_put_int_param(P4(gs_param_list * plist, gs_param_name param_name, + int *pval, int ecode)); + +/* ---------------- Vector implementation procedures ---------------- */ + + /* Imager state */ +int psdf_setlinewidth(P2(gx_device_vector * vdev, floatp width)); +int psdf_setlinecap(P2(gx_device_vector * vdev, gs_line_cap cap)); +int psdf_setlinejoin(P2(gx_device_vector * vdev, gs_line_join join)); +int psdf_setmiterlimit(P2(gx_device_vector * vdev, floatp limit)); +int psdf_setdash(P4(gx_device_vector * vdev, const float *pattern, + uint count, floatp offset)); +int psdf_setflat(P2(gx_device_vector * vdev, floatp flatness)); +int psdf_setlogop(P3(gx_device_vector * vdev, gs_logical_operation_t lop, + gs_logical_operation_t diff)); + + /* Other state */ +int psdf_setfillcolor(P2(gx_device_vector * vdev, const gx_drawing_color * pdc)); +int psdf_setstrokecolor(P2(gx_device_vector * vdev, const gx_drawing_color * pdc)); + + /* Paths */ +#define psdf_dopath gdev_vector_dopath +int psdf_dorect(P6(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, + fixed y1, gx_path_type_t type)); +int psdf_beginpath(P2(gx_device_vector * vdev, gx_path_type_t type)); +int psdf_moveto(P7(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, bool first, gx_path_type_t type)); +int psdf_lineto(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, gx_path_type_t type)); +int psdf_curveto(P10(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x1, floatp y1, floatp x2, + floatp y2, floatp x3, floatp y3, gx_path_type_t type)); +int psdf_closepath(P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x_start, floatp y_start, gx_path_type_t type)); + +/* ---------------- Binary (image) data procedures ---------------- */ + +/* Define the structure for writing binary data. */ +typedef struct psdf_binary_writer_s { + stream *strm; + gx_device_psdf *dev; +} psdf_binary_writer; + +/* Begin writing binary data. */ +int psdf_begin_binary(P2(gx_device_psdf * pdev, psdf_binary_writer * pbw)); + +/* Add an encoding filter. The client must have allocated the stream state, */ +/* if any, using pdev->v_memory. */ +int psdf_encode_binary(P3(psdf_binary_writer * pbw, + const stream_template * template, stream_state * ss)); + +/* Add a 2-D CCITTFax encoding filter. */ +int psdf_CFE_binary(P4(psdf_binary_writer * pbw, int w, int h, bool invert)); + +/* Set up compression and downsampling filters for an image. */ +/* Note that this may modify the image parameters. */ +/* If pctm is NULL, downsampling is not used. */ +/* pis only provides UCR and BG information for CMYK => RGB conversion. */ +int psdf_setup_image_filters(P5(gx_device_psdf * pdev, psdf_binary_writer * pbw, + gs_image_t * pim, const gs_matrix * pctm, + const gs_imager_state * pis)); + +/* Finish writing binary data. */ +int psdf_end_binary(P1(psdf_binary_writer * pbw)); + +/* ------ Symbolic data printing ------ */ + +/* Print a PostScript string in the most efficient form. */ +#define print_binary_ok 1 +#define print_ASCII85_ok 2 +void psdf_write_string(P4(stream * s, const byte * str, uint size, + int print_ok)); + +/* + * Create a stream that just keeps track of how much has been written + * to it. We use this for measuring data that will be stored rather + * than written to an actual stream. This too should probably migrate + * to stream.c.... + */ +int psdf_alloc_position_stream(P2(stream ** ps, gs_memory_t * mem)); + +/* + * Create/release a parameter list for printing (non-default) filter + * parameters. This should probably migrate to a lower level.... + */ +typedef struct param_printer_params_s { + const char *prefix; /* before entire object, if any params */ + const char *suffix; /* after entire object, if any params */ + const char *item_prefix; /* before each param */ + const char *item_suffix; /* after each param */ +} param_printer_params_t; + +#define param_printer_params_default_values 0, 0, 0, "\n" +extern const param_printer_params_t param_printer_params_default; +int psdf_alloc_param_printer(P5(gs_param_list ** pplist, + const param_printer_params_t * ppp, stream * s, + int print_ok, gs_memory_t * mem)); +void psdf_free_param_printer(P1(gs_param_list * plist)); + +/* Write out a Type 1 font definition. */ +#ifndef gs_font_type1_DEFINED +# define gs_font_type1_DEFINED +typedef struct gs_font_type1_s gs_font_type1; + +#endif +int psdf_embed_type1_font(P2(stream * s, gs_font_type1 * pfont)); + +/* ---------------- Other procedures ---------------- */ + +/* Set the fill or stroke color. rgs is "rg" or "RG". */ +int psdf_set_color(P3(gx_device_vector * vdev, const gx_drawing_color * pdc, + const char *rgs)); + +#endif /* gdevpsdf_INCLUDED */ diff --git a/pstoraster/gdevpsdi.c b/pstoraster/gdevpsdi.c new file mode 100644 index 0000000000..7dd3c3cb0a --- /dev/null +++ b/pstoraster/gdevpsdi.c @@ -0,0 +1,330 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Image compression for PostScript and PDF writers */ +#include "math_.h" +#include "gx.h" +#include "gserrors.h" +#include "gscspace.h" +#include "gdevpsdf.h" +#include "gdevpsds.h" +#include "jpeglib.h" /* for sdct.h */ +#include "strimpl.h" +#include "scfx.h" +#include "sdct.h" +#include "slzwx.h" +#include "spngpx.h" +#include "srlx.h" +#include "szlibx.h" + +/* ---------------- Image compression ---------------- */ + +/* Add a filter to expand or reduce the pixel width if needed. */ +/* At least one of bpc_in and bpc_out is 8; the other is 1, 2, 4, or 8. */ +private int +pixel_resize(psdf_binary_writer * pbw, int width, int num_components, + int bpc_in, int bpc_out) +{ + gs_memory_t *mem = pbw->dev->v_memory; + const stream_template *template; + stream_1248_state *st; + int code; + + if (bpc_out == bpc_in) + return 0; + if (bpc_in < 8) { + static const stream_template *const exts[5] = + { + 0, &s_1_8_template, &s_2_8_template, 0, &s_4_8_template + }; + + template = exts[bpc_in]; + } else { + static const stream_template *const rets[5] = + { + 0, &s_8_1_template, &s_8_2_template, 0, &s_8_4_template + }; + + template = rets[bpc_out]; + } + st = (stream_1248_state *) + s_alloc_state(mem, template->stype, "pixel_resize state"); + if (st == 0) + return_error(gs_error_VMerror); + code = psdf_encode_binary(pbw, template, (stream_state *) st); + if (code < 0) { + gs_free_object(mem, st, "pixel_resize state"); + return code; + } + s_1248_init(st, width, num_components); + return 0; +} + +/* Add the appropriate image compression filter, if any. */ +private int +setup_image_compression(psdf_binary_writer * pbw, const psdf_image_params * pdip, + const gs_image_t * pim) +{ + gx_device_psdf *pdev = pbw->dev; + const stream_template *template = pdip->filter_template; + stream_state *st; + + if (pdip->AutoFilter) { + /****** AutoFilter IS NYI ******/ + /* + * Even though this isn't obvious from the Adobe Tech Note, + * it appears that if UseFlateCompression is true, the default + * compressor for AutoFilter is FlateEncode, not LZWEncode. + */ + template = + (pdev->params.UseFlateCompression && + pdev->version >= psdf_version_ll3 ? + &s_zlibE_template : &s_LZWE_template); + } + if (!pdip->Encode || template == 0) /* no compression */ + return 0; + /* Only use DCTE for 8-bit data. */ + if (template == &s_DCTE_template && + !(pdip->Downsample ? + pdip->Depth == 8 || + (pdip->Depth == -1 && pim->BitsPerComponent == 8) : + pim->BitsPerComponent == 8) + ) { + /* Use LZW instead. */ + template = &s_LZWE_template; + } + st = s_alloc_state(pdev->v_memory, template->stype, + "setup_image_compression"); + if (st == 0) + return_error(gs_error_VMerror); + if (template->set_defaults) + (*template->set_defaults) (st); + if (template == &s_CFE_template) { + stream_CFE_state *const ss = (stream_CFE_state *) st; + + if (pdip->Dict != 0 && pdip->Dict->template == &s_CFE_template) { + stream_state common; + + common = *st; /* save generic info */ + *ss = *(const stream_CFE_state *)pdip->Dict; + *st = common; + } else { + ss->K = -1; + ss->BlackIs1 = true; + } + ss->Columns = pim->Width; + ss->Rows = (ss->EndOfBlock ? 0 : pim->Height); + } else if (template == &s_LZWE_template || + template == &s_zlibE_template) { + /* Add a PNGPredictor filter. */ + int code = psdf_encode_binary(pbw, template, st); + + if (code < 0) { + gs_free_object(pdev->v_memory, st, "setup_image_compression"); + return code; + } + template = &s_PNGPE_template; + st = s_alloc_state(pdev->v_memory, template->stype, + "setup_image_compression"); + if (st == 0) + return_error(gs_error_VMerror); + if (template->set_defaults) + (*template->set_defaults) (st); + { + stream_PNGP_state *const ss = (stream_PNGP_state *) st; + + ss->Colors = gs_color_space_num_components(pim->ColorSpace); + ss->Columns = pim->Width; + } + } else if (template == &s_DCTE_template) { + /****** ADD PARAMETERS FROM pdip->Dict ******/ + } { + int code = psdf_encode_binary(pbw, template, st); + + if (code < 0) { + gs_free_object(pdev->v_memory, st, "setup_image_compression"); + return code; + } + } + return 0; +} + +/* Add downsampling, antialiasing, and compression filters. */ +/* Uses AntiAlias, Depth, DownsampleType, Resolution. */ +private int +setup_downsampling(psdf_binary_writer * pbw, const psdf_image_params * pdip, + gs_image_t * pim, floatp resolution) +{ + gx_device_psdf *pdev = pbw->dev; + const stream_template *template = + (pdip->DownsampleType == ds_Average ? + &s_Average_template : &s_Subsample_template); + int factor = (int)(resolution / pdip->Resolution); + int orig_bpc = pim->BitsPerComponent; + int orig_width = pim->Width; + int orig_height = pim->Height; + stream_state *st; + int code; + + if (factor <= 1 || pim->Width < factor || pim->Height < factor) + return setup_image_compression(pbw, pdip, pim); /* no downsampling */ + st = s_alloc_state(pdev->v_memory, template->stype, + "setup_downsampling"); + if (st == 0) + return_error(gs_error_VMerror); + if (template->set_defaults) + (*template->set_defaults) (st); + { + stream_Downsample_state *const ss = (stream_Downsample_state *) st; + + ss->Colors = gs_color_space_num_components(pim->ColorSpace); + ss->Columns = pim->Width; + ss->XFactor = ss->YFactor = factor; + ss->AntiAlias = pdip->AntiAlias; + if (template->init) + (*template->init) (st); + pim->Width /= factor; + pim->Height /= factor; + pim->BitsPerComponent = pdip->Depth; + gs_matrix_scale(&pim->ImageMatrix, (double)pim->Width / orig_width, + (double)pim->Height / orig_height, + &pim->ImageMatrix); + /****** NO ANTI-ALIASING YET ******/ + if ((code = setup_image_compression(pbw, pdip, pim)) < 0 || + (code = pixel_resize(pbw, pim->Width, ss->Colors, + 8, pdip->Depth)) < 0 || + (code = psdf_encode_binary(pbw, template, st)) < 0 || + (code = pixel_resize(pbw, orig_width, ss->Colors, + orig_bpc, 8)) < 0 + ) { + gs_free_object(pdev->v_memory, st, "setup_image_compression"); + return code; + } + } + return 0; +} + +/* Set up compression and downsampling filters for an image. */ +/* Note that this may modify the image parameters. */ +int +psdf_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw, + gs_image_t * pim, const gs_matrix * pctm, + const gs_imager_state * pis) +{ /* + * The following algorithms are per Adobe Tech Note # 5151, + * "Acrobat Distiller Parameters", revised 16 September 1996 + * for Acrobat(TM) Distiller(TM) 3.0. + * + * The control structure is a little tricky, because filter + * pipelines must be constructed back-to-front. + */ + int code = 0; + psdf_image_params params; + + if (pim->ImageMask) { + params = pdev->params.MonoImage; + params.Depth = 1; + } else { + int ncomp = gs_color_space_num_components(pim->ColorSpace); + int bpc = pim->BitsPerComponent; + + /* + * We can compute the image resolution by: + * W / (W * ImageMatrix^-1 * CTM / HWResolution). + * We can replace W by 1 to simplify the computation. + */ + double resolution; + + if (pctm == 0) + resolution = -1; + else { + gs_point pt; + + /* We could do both X and Y, but why bother? */ + gs_distance_transform_inverse(1.0, 0.0, &pim->ImageMatrix, &pt); + gs_distance_transform(pt.x, pt.y, pctm, &pt); + resolution = 1.0 / hypot(pt.x / pdev->HWResolution[0], + pt.y / pdev->HWResolution[1]); + } + if (ncomp == 1) { + /* Monochrome or gray */ + if (bpc == 1) + params = pdev->params.MonoImage; + else + params = pdev->params.GrayImage; + if (params.Depth == -1) + params.Depth = bpc; + /* Check for downsampling. */ + if (params.Downsample && params.Resolution <= resolution / 2) { + /* Use the downsampled depth, not the original data depth. */ + if (params.Depth == 1) { + params.Filter = pdev->params.MonoImage.Filter; + params.filter_template = pdev->params.MonoImage.filter_template; + params.Dict = pdev->params.MonoImage.Dict; + } else { + params.Filter = pdev->params.GrayImage.Filter; + params.filter_template = pdev->params.GrayImage.filter_template; + params.Dict = pdev->params.GrayImage.Dict; + } + code = setup_downsampling(pbw, ¶ms, pim, resolution); + } else { + code = setup_image_compression(pbw, ¶ms, pim); + } + } else { + /* Color */ + bool cmyk_to_rgb = + pdev->params.ConvertCMYKImagesToRGB && + pis != 0 && + gs_color_space_get_index(pim->ColorSpace) == + gs_color_space_index_DeviceCMYK; + + if (cmyk_to_rgb) + pim->ColorSpace = gs_cspace_DeviceRGB(pis); + params = pdev->params.ColorImage; + if (params.Depth == -1) + params.Depth = (cmyk_to_rgb ? 8 : bpc); + if (params.Downsample && params.Resolution <= resolution / 2) { + code = setup_downsampling(pbw, ¶ms, pim, resolution); + } else { + code = setup_image_compression(pbw, ¶ms, pim); + } + if (cmyk_to_rgb) { + gs_memory_t *mem = pdev->v_memory; + stream_C2R_state *ss = (stream_C2R_state *) + s_alloc_state(mem, s_C2R_template.stype, "C2R state"); + int code = pixel_resize(pbw, pim->Width, 3, 8, bpc); + + if (code < 0 || + (code = psdf_encode_binary(pbw, &s_C2R_template, + (stream_state *) ss)) < 0 || + (code = pixel_resize(pbw, pim->Width, 4, bpc, 8)) < 0 + ) + return code; + s_C2R_init(ss, pis); + } + } + } + return code; +} diff --git a/pstoraster/gdevpsdp.c b/pstoraster/gdevpsdp.c new file mode 100644 index 0000000000..ba19460525 --- /dev/null +++ b/pstoraster/gdevpsdp.c @@ -0,0 +1,669 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* (Distiller) parameter handling for PostScript and PDF writers */ +#include "string_.h" +#include "gx.h" +#include "gserrors.h" +#include "gxdevice.h" +#include "gdevpsdf.h" +#include "gdevpstr.h" +#include "strimpl.h" /* for short-sighted compilers */ +#include "scfx.h" +#include "jpeglib.h" /* for sdct.h */ +#include "sdct.h" +#include "slzwx.h" +#include "srlx.h" +#include "szlibx.h" + +/* ---------------- Get/put Distiller parameters ---------------- */ + +/* + * This code handles all the Distiller parameters except the *ACSDict and + * *ImageDict parameter dictionaries. (It doesn't cause any of the + * parameters actually to have any effect.) + */ + +typedef struct psdf_image_filter_name_s { + const char *pname; + const stream_template *template; + psdf_version min_version; +} psdf_image_filter_name; +typedef struct psdf_image_param_names_s { + const char *ACSDict; /* not used for mono */ + const char *AntiAlias; + const char *AutoFilter; /* not used for mono */ + const char *Depth; + const char *Dict; + const char *Downsample; + const char *DownsampleType; + const char *Encode; + const char *Filter; + const char *Resolution; +} psdf_image_param_names; +private const psdf_image_param_names Color_names = +{ + "ColorACSImageDict", "AntiAliasColorImages", "AutoFilterColorImages", + "ColorImageDepth", "ColorImageDict", + "DownsampleColorImages", "ColorImageDownsampleType", "EncodeColorImages", + "ColorImageFilter", "ColorImageResolution" +}; +private const psdf_image_filter_name Poly_filters[] = +{ + {"DCTEncode", &s_DCTE_template}, + {"FlateEncode", &s_zlibE_template, psdf_version_ll3}, + {"LZWEncode", &s_LZWE_template}, + {0, 0} +}; +private const psdf_image_param_names Gray_names = +{ + "GrayACSImageDict", "AntiAliasGrayImages", "AutoFilterGrayImages", + "GrayImageDepth", "GrayImageDict", + "DownsampleGrayImages", "GrayImageDownsampleType", "EncodeGrayImages", + "GrayImageFilter", "GrayImageResolution" +}; +private const psdf_image_param_names Mono_names = +{ + 0, "AntiAliasMonoImages", 0, + "MonoImageDepth", "MonoImageDict", + "DownsampleMonoImages", "MonoImageDownsampleType", "EncodeMonoImages", + "MonoImageFilter", "MonoImageResolution" +}; +private const psdf_image_filter_name Mono_filters[] = +{ + {"CCITTFaxEncode", &s_CFE_template}, + {"FlateEncode", &s_zlibE_template, psdf_version_ll3}, + {"LZWEncode", &s_LZWE_template}, + {"RunLengthEncode", &s_RLE_template}, + {0, 0} +}; +private const char *const AutoRotatePages_names[] = +{ + "None", "All", "PageByPage", 0 +}; +private const char *const ColorConversionStrategy_names[] = +{ + "LeaveColorUnchanged", "UseDeviceDependentColor", + "UseDeviceIndependentColor", 0 +}; +private const char *const DownsampleType_names[] = +{ + "Average", "Subsample", 0 +}; +private const char *const TransferFunctionInfo_names[] = +{ + "Preserve", "Apply", "Remove", 0 +}; +private const char *const UCRandBGInfo_names[] = +{ + "Preserve", "Remove", 0 +}; + +/* -------- Get parameters -------- */ + +extern stream_state_proc_get_params(s_DCTE_get_params, stream_DCT_state); +extern stream_state_proc_get_params(s_CF_get_params, stream_CF_state); +typedef stream_state_proc_get_params((*ss_get_params_t), stream_state); + +private int +psdf_CF_get_params(gs_param_list * plist, const stream_state * ss, bool all) +{ + return (ss == 0 ? 0 : + s_CF_get_params(plist, (const stream_CF_state *)ss, all)); +} +private int +psdf_DCT_get_params(gs_param_list * plist, const stream_state * ss, bool all) +{ + int code = (ss == 0 ? 0 : + s_DCTE_get_params(plist, (const stream_DCT_state *)ss, all)); + /* + * Add dummy Columns, Rows, and Colors parameters so that put_params + * won't complain. + */ + int dummy_size = 8, dummy_colors = 3; + + if (code < 0 || + (code = param_write_int(plist, "Columns", &dummy_size)) < 0 || + (code = param_write_int(plist, "Rows", &dummy_size)) < 0 || + (code = param_write_int(plist, "Colors", &dummy_colors)) < 0 + ) + return code; + return 0; +} + +/* + * Get an image Dict parameter. Note that we return a default (usually + * empty) dictionary if the parameter has never been set. + */ +private int +psdf_get_image_dict_param(gs_param_list * plist, const gs_param_name pname, + stream_state * ss, ss_get_params_t get_params) +{ + gs_param_dict dict; + int code; + + if (pname == 0) + return 0; + dict.size = 12; /* enough for all param dicts we know about */ + if ((code = param_begin_write_dict(plist, pname, &dict, false)) < 0) + return code; + code = (*get_params)(dict.list, ss, false); + param_end_write_dict(plist, pname, &dict); + return code; +} + +/* Get a set of image-related parameters. */ +private int +psdf_get_image_params(gs_param_list * plist, + const psdf_image_param_names * pnames, psdf_image_params * params) +{ + int code; + gs_param_string dsts, fs; + + param_string_from_string(dsts, + DownsampleType_names[params->DownsampleType]); + if ( + (code = psdf_get_image_dict_param(plist, pnames->ACSDict, + params->ACSDict, + psdf_DCT_get_params)) < 0 || + (code = param_write_bool(plist, pnames->AntiAlias, + ¶ms->AntiAlias)) < 0 || + (pnames->AutoFilter != 0 && + (code = param_write_bool(plist, pnames->AutoFilter, + ¶ms->AutoFilter)) < 0) || + (code = param_write_int(plist, pnames->Depth, + ¶ms->Depth)) < 0 || + (code = psdf_get_image_dict_param(plist, pnames->Dict, + params->Dict, + (params->Dict == 0 || + params->Dict->template == + &s_CFE_template ? + psdf_CF_get_params : + psdf_DCT_get_params))) < 0 || + (code = param_write_bool(plist, pnames->Downsample, + ¶ms->Downsample)) < 0 || + (code = param_write_name(plist, pnames->DownsampleType, + &dsts)) < 0 || + (code = param_write_bool(plist, pnames->Encode, + ¶ms->Encode)) < 0 || + (code = (params->Filter == 0 ? 0 : + (param_string_from_string(fs, params->Filter), + param_write_name(plist, pnames->Filter, &fs)))) < 0 || + (code = param_write_int(plist, pnames->Resolution, + ¶ms->Resolution)) < 0 + ) + DO_NOTHING; + return code; +} + +/* Get parameters. */ +int +gdev_psdf_get_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_psdf *pdev = (gx_device_psdf *) dev; + int code = gdev_vector_get_params(dev, plist); + gs_param_string arps, ccss, tfis, ucrbgis; + + if (code < 0) + return code; + param_string_from_string(arps, + AutoRotatePages_names[(int)pdev->params.AutoRotatePages]); + param_string_from_string(ccss, + ColorConversionStrategy_names[(int)pdev->params.ColorConversionStrategy]); + param_string_from_string(tfis, + TransferFunctionInfo_names[(int)pdev->params.TransferFunctionInfo]); + param_string_from_string(ucrbgis, + UCRandBGInfo_names[(int)pdev->params.UCRandBGInfo]); + if ( + /* General parameters */ + + (code = param_write_bool(plist, "ASCII85EncodePages", + &pdev->params.ASCII85EncodePages)) < 0 || + (code = param_write_name(plist, "AutoRotatePages", + &arps)) < 0 || + (code = param_write_bool(plist, "CompressPages", + &pdev->params.CompressPages)) < 0 || + (code = param_write_long(plist, "ImageMemory", + &pdev->params.ImageMemory)) < 0 || + (code = param_write_bool(plist, "LZWEncodePages", + &pdev->params.LZWEncodePages)) < 0 || + (code = param_write_bool(plist, "PreserveHalftoneInfo", + &pdev->params.PreserveHalftoneInfo)) < 0 || + (code = param_write_bool(plist, "PreserveOPIComments", + &pdev->params.PreserveOPIComments)) < 0 || + (code = param_write_bool(plist, "PreserveOverprintSettings", + &pdev->params.PreserveOverprintSettings)) < 0 || + (code = param_write_name(plist, "TransferFunctionInfo", &tfis)) < 0 || + (code = param_write_name(plist, "UCRandBGInfo", &ucrbgis)) < 0 || + (code = param_write_bool(plist, "UseFlateCompression", + &pdev->params.UseFlateCompression)) < 0 || + + /* Color sampled image parameters */ + + (code = psdf_get_image_params(plist, &Color_names, &pdev->params.ColorImage)) < 0 || + (code = param_write_name(plist, "ColorConversionStrategy", + &ccss)) < 0 || + (code = param_write_bool(plist, "ConvertCMYKImagesToRGB", + &pdev->params.ConvertCMYKImagesToRGB)) < 0 || + (code = param_write_bool(plist, "ConvertImagesToIndexed", + &pdev->params.ConvertImagesToIndexed)) < 0 || + + /* Gray sampled image parameters */ + + (code = psdf_get_image_params(plist, &Gray_names, &pdev->params.GrayImage)) < 0 || + + /* Mono sampled image parameters */ + + (code = psdf_get_image_params(plist, &Mono_names, &pdev->params.MonoImage)) < 0 || + + /* Font embedding parameters */ + + (code = param_write_name_array(plist, "AlwaysEmbed", &pdev->params.AlwaysEmbed)) < 0 || + (code = param_write_name_array(plist, "NeverEmbed", &pdev->params.NeverEmbed)) < 0 || + (code = param_write_bool(plist, "EmbedAllFonts", &pdev->params.EmbedAllFonts)) < 0 || + (code = param_write_bool(plist, "SubsetFonts", &pdev->params.SubsetFonts)) < 0 || + (code = param_write_int(plist, "MaxSubsetPct", &pdev->params.MaxSubsetPct)) < 0 + ); + return code; +} + +/* -------- Put parameters -------- */ + +extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state); +extern stream_state_proc_put_params(s_CF_put_params, stream_CF_state); +typedef stream_state_proc_put_params((*ss_put_params_t), stream_state); + +private int +psdf_CF_put_params(gs_param_list * plist, stream_state * st) +{ + stream_CFE_state *const ss = (stream_CFE_state *) st; + + (*s_CFE_template.set_defaults) (st); + ss->K = -1; + ss->BlackIs1 = true; + return s_CF_put_params(plist, (stream_CF_state *) ss); +} +private int +psdf_DCT_put_params(gs_param_list * plist, stream_state * ss) +{ + return s_DCTE_put_params(plist, (stream_DCT_state *) ss); +} + +/* Compare a C string and a gs_param_string. */ +bool +psdf_key_eq(const gs_param_string * pcs, const char *str) +{ + return (strlen(str) == pcs->size && + !strncmp(str, (const char *)pcs->data, pcs->size)); +} + +/* Put an enumerated value. */ +private int +psdf_put_enum_param(gs_param_list * plist, gs_param_name param_name, + int *pvalue, const char *const pnames[], int ecode) +{ + gs_param_string ens; + int code = param_read_name(plist, param_name, &ens); + + switch (code) { + case 1: + return ecode; + case 0: + { + int i; + + for (i = 0; pnames[i] != 0; ++i) + if (psdf_key_eq(&ens, pnames[i])) { + *pvalue = i; + return 0; + } + } + code = gs_error_rangecheck; + default: + ecode = code; + param_signal_error(plist, param_name, code); + } + return code; +} + +/* Put a Boolean or integer parameter. */ +int +psdf_put_bool_param(gs_param_list * plist, gs_param_name param_name, + bool * pval, int ecode) +{ + int code; + + switch (code = param_read_bool(plist, param_name, pval)) { + default: + ecode = code; + param_signal_error(plist, param_name, ecode); + case 0: + case 1: + break; + } + return ecode; +} +int +psdf_put_int_param(gs_param_list * plist, gs_param_name param_name, + int *pval, int ecode) +{ + int code; + + switch (code = param_read_int(plist, param_name, pval)) { + default: + ecode = code; + param_signal_error(plist, param_name, ecode); + case 0: + case 1: + break; + } + return ecode; +} + +/* Put [~](Always|Never)Embed parameters. */ +private int +psdf_put_embed_param(gs_param_list * plist, gs_param_name notpname, + gs_param_string_array * psa, int ecode) +{ + gs_param_name pname = notpname + 1; + int code; + gs_param_string_array nsa; + +/***** Storage management is incomplete ******/ +/***** Doesn't do incremental add/delete ******/ + switch (code = param_read_name_array(plist, pname, psa)) { + default: + ecode = code; + param_signal_error(plist, pname, ecode); + case 0: + case 1: + break; + } + switch (code = param_read_name_array(plist, notpname, &nsa)) { + default: + ecode = code; + param_signal_error(plist, notpname, ecode); + case 0: + case 1: + break; + } + return ecode; +} + +/* Put an image Dict parameter. */ +private int +psdf_put_image_dict_param(gs_param_list * plist, const gs_param_name pname, + stream_state ** pss, const stream_template * template, + ss_put_params_t put_params, gs_memory_t * mem) +{ + gs_param_dict dict; + stream_state *ss = *pss; + int code; + + switch (code = param_begin_read_dict(plist, pname, &dict, false)) { + default: + param_signal_error(plist, pname, code); + return code; + case 1: + ss = 0; + break; + case 0:{ + /****** + ****** THIS CAUSES A SEGV FOR DCT FILTERS, BECAUSE + ****** THEY DON'T INTIALIZE PROPERLY. + ******/ + if (template != &s_DCTE_template) { + stream_state *ss_new = + s_alloc_state(mem, template->stype, pname); + + if (ss_new == 0) + return_error(gs_error_VMerror); + ss_new->template = template; + if (template->set_defaults) + (*template->set_defaults)(ss_new); + code = (*put_params)(dict.list, ss_new); + if (code < 0) { + param_signal_error(plist, pname, code); + /* Make sure we free the new state. */ + *pss = ss_new; + } else + ss = ss_new; + } + } + param_end_read_dict(plist, pname, &dict); + } + if (*pss != ss) { + if (ss) { + /****** FREE SUBSIDIARY OBJECTS -- HOW? ******/ + gs_free_object(mem, *pss, pname); + } + *pss = ss; + } + return code; +} + +/* Put a set of image-related parameters. */ +private int +psdf_put_image_params(const gx_device_psdf * pdev, gs_param_list * plist, + const psdf_image_param_names * pnames, const psdf_image_filter_name * pifn, + psdf_image_params * params, int ecode) +{ + gs_param_string fs; + + /* + * Since this procedure can be called before the device is open, + * we must use pdev->memory rather than pdev->v_memory. + */ + gs_memory_t *mem = pdev->memory; + gs_param_name pname; + int dsti = params->DownsampleType; + int code; + + if ((pname = pnames->ACSDict) != 0) { + code = psdf_put_image_dict_param(plist, pname, ¶ms->ACSDict, + &s_DCTE_template, + psdf_DCT_put_params, mem); + if (code < 0) + ecode = code; + } + ecode = psdf_put_bool_param(plist, pnames->AntiAlias, + ¶ms->AntiAlias, ecode); + if (pnames->AutoFilter) + ecode = psdf_put_bool_param(plist, pnames->AutoFilter, + ¶ms->AutoFilter, ecode); + ecode = psdf_put_int_param(plist, pnames->Depth, + ¶ms->Depth, ecode); + if ((pname = pnames->Dict) != 0) { + const stream_template *template; + ss_put_params_t put_params; + + /* Hack to determine what kind of a Dict we want: */ + if (pnames->Dict[0] == 'M') + template = &s_CFE_template, + put_params = psdf_CF_put_params; + else + template = &s_DCTE_template, + put_params = psdf_DCT_put_params; + code = psdf_put_image_dict_param(plist, pname, ¶ms->Dict, + template, put_params, mem); + if (code < 0) + ecode = code; + } + ecode = psdf_put_bool_param(plist, pnames->Downsample, + ¶ms->Downsample, ecode); + if ((ecode = psdf_put_enum_param(plist, pnames->DownsampleType, + &dsti, DownsampleType_names, + ecode)) >= 0 + ) + params->DownsampleType = (enum psdf_downsample_type)dsti; + ecode = psdf_put_bool_param(plist, pnames->Encode, + ¶ms->Encode, ecode); + switch (code = param_read_string(plist, pnames->Filter, &fs)) { + case 0: + { + const psdf_image_filter_name *pn = pifn; + + while (pn->pname != 0 && !psdf_key_eq(&fs, pn->pname)) + pn++; + if (pn->pname == 0 || pn->min_version > pdev->version) { + ecode = gs_error_rangecheck; + goto ipe; + } + params->Filter = pn->pname; + params->filter_template = pn->template; + break; + } + default: + ecode = code; + ipe:param_signal_error(plist, pnames->Filter, ecode); + case 1: + break; + } + ecode = psdf_put_int_param(plist, pnames->Resolution, + ¶ms->Resolution, ecode); + if (ecode >= 0) { /* Force parameters to acceptable values. */ + if (params->Resolution < 1) + params->Resolution = 1; + switch (params->Depth) { + default: + params->Depth = -1; + case 1: + case 2: + case 4: + case 8: + case -1: + break; + } + } + return ecode; +} + +/* Put parameters. */ +int +gdev_psdf_put_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_psdf *pdev = (gx_device_psdf *) dev; + int ecode = 0; + int code; + gs_param_name param_name; + psdf_distiller_params params; + + /* General parameters. */ + + params = pdev->params; + + ecode = psdf_put_bool_param(plist, "ASCII85EncodePages", + ¶ms.ASCII85EncodePages, ecode); + { + int arpi = params.AutoRotatePages; + + ecode = psdf_put_enum_param(plist, "AutoRotatePages", &arpi, + AutoRotatePages_names, ecode); + params.AutoRotatePages = (enum psdf_auto_rotate_pages)arpi; + } + ecode = psdf_put_bool_param(plist, "CompressPages", + ¶ms.CompressPages, ecode); + switch (code = param_read_long(plist, (param_name = "ImageMemory"), ¶ms.ImageMemory)) { + default: + ecode = code; + param_signal_error(plist, param_name, ecode); + case 0: + case 1: + break; + } + ecode = psdf_put_bool_param(plist, "LZWEncodePages", + ¶ms.LZWEncodePages, ecode); + ecode = psdf_put_bool_param(plist, "PreserveHalftoneInfo", + ¶ms.PreserveHalftoneInfo, ecode); + ecode = psdf_put_bool_param(plist, "PreserveOPIComments", + ¶ms.PreserveOPIComments, ecode); + ecode = psdf_put_bool_param(plist, "PreserveOverprintSettings", + ¶ms.PreserveOverprintSettings, ecode); + { + int tfii = params.TransferFunctionInfo; + + ecode = psdf_put_enum_param(plist, "TransferFunctionInfo", &tfii, + TransferFunctionInfo_names, ecode); + params.TransferFunctionInfo = (enum psdf_transfer_function_info)tfii; + } + { + int ucrbgi = params.UCRandBGInfo; + + ecode = psdf_put_enum_param(plist, "UCRandBGInfo", &ucrbgi, + UCRandBGInfo_names, ecode); + params.UCRandBGInfo = (enum psdf_ucr_and_bg_info)ucrbgi; + } + ecode = psdf_put_bool_param(plist, "UseFlateCompression", + ¶ms.UseFlateCompression, ecode); + + /* Color sampled image parameters */ + + ecode = psdf_put_image_params(pdev, plist, &Color_names, Poly_filters, + ¶ms.ColorImage, ecode); + { + int ccsi = params.ColorConversionStrategy; + + ecode = psdf_put_enum_param(plist, "ColorConversionStrategy", &ccsi, + ColorConversionStrategy_names, ecode); + params.ColorConversionStrategy = + (enum psdf_color_conversion_strategy)ccsi; + } + ecode = psdf_put_bool_param(plist, "ConvertCMYKImagesToRGB", + ¶ms.ConvertCMYKImagesToRGB, ecode); + ecode = psdf_put_bool_param(plist, "ConvertImagesToIndexed", + ¶ms.ConvertImagesToIndexed, ecode); + + /* Gray sampled image parameters */ + + ecode = psdf_put_image_params(pdev, plist, &Gray_names, Poly_filters, + ¶ms.GrayImage, ecode); + + /* Mono sampled image parameters */ + + ecode = psdf_put_image_params(pdev, plist, &Mono_names, Mono_filters, + ¶ms.MonoImage, ecode); + + /* Font embedding parameters */ + + ecode = psdf_put_embed_param(plist, "~AlwaysEmbed", + ¶ms.AlwaysEmbed, ecode); + ecode = psdf_put_embed_param(plist, "~NeverEmbed", + ¶ms.NeverEmbed, ecode); + ecode = psdf_put_bool_param(plist, "EmbedAllFonts", + ¶ms.EmbedAllFonts, ecode); + ecode = psdf_put_bool_param(plist, "SubsetFonts", + ¶ms.SubsetFonts, ecode); + ecode = psdf_put_int_param(plist, "MaxSubsetPct", + ¶ms.MaxSubsetPct, ecode); + + if (ecode < 0) + return ecode; + code = gdev_vector_put_params(dev, plist); + if (code < 0) + return code; + + pdev->params = params; /* OK to update now */ + return 0; +} diff --git a/pstoraster/gdevpsds.c b/pstoraster/gdevpsds.c new file mode 100644 index 0000000000..da128b5b7d --- /dev/null +++ b/pstoraster/gdevpsds.c @@ -0,0 +1,470 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Image processing streams for PostScript and PDF writers */ +#include "gx.h" +#include "memory_.h" +#include "gserrors.h" +#include "gxdcconv.h" +#include "gdevpsds.h" + +/* ---------------- Convert between 1/2/4 and 8 bits ---------------- */ +gs_private_st_simple(st_1248_state, stream_1248_state, "stream_1248_state"); + +/* Initialize the state. */ +private int +s_1_init(stream_state * st) +{ + stream_1248_state *const ss = (stream_1248_state *) st; + + ss->left = ss->samples_per_row; + ss->bits_per_sample = 1; + return 0; +} +private int +s_2_init(stream_state * st) +{ + stream_1248_state *const ss = (stream_1248_state *) st; + + ss->left = ss->samples_per_row; + ss->bits_per_sample = 2; + return 0; +} +private int +s_4_init(stream_state * st) +{ + stream_1248_state *const ss = (stream_1248_state *) st; + + ss->left = ss->samples_per_row; + ss->bits_per_sample = 4; + return 0; +} + +/* Process one buffer. */ +#define BEGIN_1248\ + stream_1248_state * const ss = (stream_1248_state *)st;\ + const byte *p = pr->ptr;\ + const byte *rlimit = pr->limit;\ + byte *q = pw->ptr;\ + byte *wlimit = pw->limit;\ + uint left = ss->left;\ + int status;\ + int n +#define END_1248\ + pr->ptr = p;\ + pw->ptr = q;\ + ss->left = left;\ + return status + +/* N-to-8 expansion */ +#define FOREACH_N_8(in, nout)\ + status = 0;\ + for ( ; p < rlimit; left -= n, q += n, ++p ) {\ + byte in = p[1];\ + n = min(left, nout);\ + if ( wlimit - q < n ) {\ + status = 1;\ + break;\ + }\ + switch ( n ) {\ + case 0: left = ss->samples_per_row; --p; continue; +#define END_FOREACH_N_8\ + }\ + } +private int +s_N_8_process(stream_state * st, stream_cursor_read * pr, + stream_cursor_write * pw, bool last) +{ + BEGIN_1248; + + switch (ss->bits_per_sample) { + + case 1:{ + FOREACH_N_8(in, 8) + case 8: + q[8] = (byte) - (in & 1); + case 7: + q[7] = (byte) - ((in >> 1) & 1); + case 6: + q[6] = (byte) - ((in >> 2) & 1); + case 5: + q[5] = (byte) - ((in >> 3) & 1); + case 4: + q[4] = (byte) - ((in >> 4) & 1); + case 3: + q[3] = (byte) - ((in >> 5) & 1); + case 2: + q[2] = (byte) - ((in >> 6) & 1); + case 1: + q[1] = (byte) - (in >> 7); + END_FOREACH_N_8; + } + break; + + case 2:{ + static const byte b2[4] = + {0x00, 0x55, 0xaa, 0xff}; + + FOREACH_N_8(in, 4) + case 4: + q[4] = b2[in & 3]; + case 3: + q[3] = b2[(in >> 2) & 3]; + case 2: + q[2] = b2[(in >> 4) & 3]; + case 1: + q[1] = b2[in >> 6]; + END_FOREACH_N_8; + } + break; + + case 4:{ + static const byte b4[16] = + { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff + }; + + FOREACH_N_8(in, 2) + case 2: + q[2] = b4[in & 0xf]; + case 1: + q[1] = b4[in >> 4]; + END_FOREACH_N_8; + } + break; + + default: + return ERRC; + } + + END_1248; +} + +/* 8-to-N reduction */ +#define FOREACH_8_N(out, nin)\ + byte out;\ + status = 1;\ + for ( ; q < wlimit; left -= n, p += n, ++q ) {\ + n = min(left, nin);\ + if ( rlimit - p < n ) {\ + status = 0;\ + break;\ + }\ + out = 0;\ + switch ( n ) {\ + case 0: left = ss->samples_per_row; --q; continue; +#define END_FOREACH_8_N\ + q[1] = out;\ + }\ + } +private int +s_8_N_process(stream_state * st, stream_cursor_read * pr, + stream_cursor_write * pw, bool last) +{ + BEGIN_1248; + + switch (ss->bits_per_sample) { + + case 1:{ + FOREACH_8_N(out, 8) + case 8: + out = p[8] >> 7; + case 7: + out |= (p[7] >> 7) << 1; + case 6: + out |= (p[6] >> 7) << 2; + case 5: + out |= (p[5] >> 7) << 3; + case 4: + out |= (p[4] >> 7) << 4; + case 3: + out |= (p[3] >> 7) << 5; + case 2: + out |= (p[2] >> 7) << 6; + case 1: + out |= p[1] & 0x80; + END_FOREACH_8_N; + } + break; + + case 2:{ + FOREACH_8_N(out, 4) + case 4: + out |= p[4] >> 6; + case 3: + out |= (p[3] >> 6) << 2; + case 2: + out |= (p[2] >> 6) << 4; + case 1: + out |= p[1] & 0xc0; + END_FOREACH_8_N; + } + break; + + case 4:{ + FOREACH_8_N(out, 2) + case 2: + out |= p[2] >> 4; + case 1: + out |= p[1] & 0xf0; + END_FOREACH_8_N; + } + break; + + default: + return ERRC; + } + + END_1248; +} + +const stream_template s_1_8_template = +{ + &st_1248_state, s_1_init, s_N_8_process, 1, 8 +}; +const stream_template s_2_8_template = +{ + &st_1248_state, s_2_init, s_N_8_process, 1, 4 +}; +const stream_template s_4_8_template = +{ + &st_1248_state, s_4_init, s_N_8_process, 1, 2 +}; + +const stream_template s_8_1_template = +{ + &st_1248_state, s_1_init, s_8_N_process, 8, 1 +}; +const stream_template s_8_2_template = +{ + &st_1248_state, s_2_init, s_8_N_process, 4, 1 +}; +const stream_template s_8_4_template = +{ + &st_1248_state, s_4_init, s_8_N_process, 2, 1 +}; + +/* ---------------- CMYK => RGB conversion ---------------- */ + +private_st_C2R_state(); + +/* Process one buffer. */ +private int +s_C2R_process(stream_state * st, stream_cursor_read * pr, + stream_cursor_write * pw, bool last) +{ + stream_C2R_state *const ss = (stream_C2R_state *) st; + const byte *p = pr->ptr; + const byte *rlimit = pr->limit; + byte *q = pw->ptr; + byte *wlimit = pw->limit; + + for (; rlimit - p >= 4 && wlimit - q >= 3; p += 4, q += 3) { + byte bc = p[1], bm = p[2], by = p[3], bk = p[4]; + frac rgb[3]; + + color_cmyk_to_rgb(byte2frac(bc), byte2frac(bm), byte2frac(by), + byte2frac(bk), ss->pis, rgb); + q[1] = frac2byte(rgb[0]); + q[2] = frac2byte(rgb[1]); + q[3] = frac2byte(rgb[2]); + } + pr->ptr = p; + pw->ptr = q; + return (rlimit - p < 4 ? 0 : 1); +} + +const stream_template s_C2R_template = +{ + &st_C2R_state, 0 /*NULL */ , s_C2R_process, 4, 3 +}; + +/* ---------------- Downsampling ---------------- */ + +private void +s_Downsample_set_defaults(register stream_state * st) +{ + stream_Downsample_state *const ss = + (stream_Downsample_state *) st; + + s_Downsample_set_defaults_inline(ss); +} + +/* Subsample */ +/****** DOESN'T IMPLEMENT padY YET ******/ + +gs_private_st_simple(st_Subsample_state, stream_Subsample_state, + "stream_Subsample_state"); + +/* Initialize the state. */ +private int +s_Subsample_init(stream_state * st) +{ + stream_Subsample_state *const ss = (stream_Subsample_state *) st; + + ss->x = ss->y = 0; + return 0; +} + +/* Process one buffer. */ +private int +s_Subsample_process(stream_state * st, stream_cursor_read * pr, + stream_cursor_write * pw, bool last) +{ + stream_Subsample_state *const ss = (stream_Subsample_state *) st; + const byte *p = pr->ptr; + const byte *rlimit = pr->limit; + byte *q = pw->ptr; + byte *wlimit = pw->limit; + int spp = ss->Colors; + int width = ss->Columns; + int xf = ss->XFactor, yf = ss->YFactor; + int xf2 = xf / 2, yf2 = yf / 2; + int xlimit = (width / xf) * xf; + int xlast = (ss->padX && xlimit < width ? xlimit + (width % xf) / 2 : -1); + int x = ss->x, y = ss->y; + int status = 0; + + for (; rlimit - p >= spp; p += spp) { + if (y == yf2 && ((x % xf == xf2 && x < xlimit) || x == xlast)) { + if (wlimit - q < spp) { + status = 1; + break; + } + memcpy(q + 1, p + 1, spp); + q += spp; + } + if (++x == width) { + x = 0; + if (++y == yf) { + y = 0; + } + } + } + pr->ptr = p; + pw->ptr = q; + ss->x = x, ss->y = y; + return status; +} + +const stream_template s_Subsample_template = +{ + &st_Subsample_state, s_Subsample_init, s_Subsample_process, 4, 4, + 0 /* NULL */, s_Downsample_set_defaults +}; + +/* Average */ + +private_st_Average_state(); + +/* Initialize the state. */ +private int +s_Average_init(stream_state * st) +{ + stream_Average_state *const ss = (stream_Average_state *) st; + + ss->sum_size = + ss->Colors * ((ss->Columns + ss->XFactor - 1) / ss->XFactor); + ss->copy_size = ss->sum_size - + (ss->padX || (ss->Columns % ss->XFactor == 0) ? 0 : ss->Colors); + ss->sums = + (uint *)gs_alloc_byte_array(st->memory, ss->sum_size, + sizeof(uint), "Average sums"); + if (ss->sums == 0) + return ERRC; /****** WRONG ******/ + memset(ss->sums, 0, ss->sum_size * sizeof(uint)); + return s_Subsample_init(st); +} + +/* Release the state. */ +private void +s_Average_release(stream_state * st) +{ + stream_Average_state *const ss = (stream_Average_state *) st; + + gs_free_object(st->memory, ss->sums, "Average sums"); +} + +/* Process one buffer. */ +private int +s_Average_process(stream_state * st, stream_cursor_read * pr, + stream_cursor_write * pw, bool last) +{ + stream_Average_state *const ss = (stream_Average_state *) st; + const byte *p = pr->ptr; + const byte *rlimit = pr->limit; + byte *q = pw->ptr; + byte *wlimit = pw->limit; + int spp = ss->Colors; + int width = ss->Columns; + int xf = ss->XFactor, yf = ss->YFactor; + int x = ss->x, y = ss->y; + uint *sums = ss->sums; + int status = 0; + +top: + if (y == yf || (last && p >= rlimit && ss->padY && y != 0)) { + /* We're copying averaged values to the output. */ + int ncopy = min(ss->copy_size - x, wlimit - q); + + if (ncopy) { + int scale = xf * y; + + while (--ncopy >= 0) + *++q = (byte) (sums[x++] / scale); + } + if (x < ss->copy_size) { + status = 1; + goto out; + } + /* Done copying. */ + x = y = 0; + memset(sums, 0, ss->sum_size * sizeof(uint)); + } + while (rlimit - p >= spp) { + uint *bp = sums + x / xf * spp; + int i; + + for (i = spp; --i >= 0;) + *bp++ += *++p; + if (++x == width) { + x = 0; + ++y; + goto top; + } + } +out: + pr->ptr = p; + pw->ptr = q; + ss->x = x, ss->y = y; + return status; +} + +const stream_template s_Average_template = +{ + &st_Average_state, s_Average_init, s_Average_process, 4, 4, + s_Average_release, s_Downsample_set_defaults +}; diff --git a/pstoraster/gdevpsds.h b/pstoraster/gdevpsds.h new file mode 100644 index 0000000000..772c1ff535 --- /dev/null +++ b/pstoraster/gdevpsds.h @@ -0,0 +1,110 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Image processing stream interface for PostScript and PDF writers */ + +#ifndef gdevpsds_INCLUDED +# define gdevpsds_INCLUDED + +#include "strimpl.h" + +/* Convert between 1/2/4 bits and 8 bits. */ +typedef struct stream_1248_state_s { + stream_state_common; + /* The following are set at initialization time. */ + uint samples_per_row; /* >0 */ + int bits_per_sample; /* 1, 2, 4 */ + /* The following are updated dynamically. */ + uint left; /* # of samples left in current row */ +} stream_1248_state; + +/* Expand N (1, 2, 4) bits to 8. */ +extern const stream_template s_1_8_template; +extern const stream_template s_2_8_template; +extern const stream_template s_4_8_template; + +/* Reduce 8 bits to N (1, 2, 4) */ +extern const stream_template s_8_1_template; +extern const stream_template s_8_2_template; +extern const stream_template s_8_4_template; + +/* Initialize an expansion or reduction stream. */ +#define s_1248_init(ss, Columns, samples_per_pixel)\ + ((ss)->samples_per_row = (Columns) * (samples_per_pixel),\ + (*(ss)->template->init)((stream_state *)(ss))) + +/* Convert (8-bit) CMYK to RGB. */ +typedef struct stream_C2R_state_s { + stream_state_common; + /* The following are set at initialization time. */ + const gs_imager_state *pis; /* for UCR & BG */ +} stream_C2R_state; + +#define private_st_C2R_state() /* in gdevpsds.c */\ + gs_private_st_ptrs1(st_C2R_state, stream_C2R_state, "stream_C2R_state",\ + c2r_enum_ptrs, c2r_reloc_ptrs, pis) +extern const stream_template s_C2R_template; + +#define s_C2R_init(ss, pisv)\ + ((ss)->pis = (pisv), 0) + +/* Downsample, possibly with anti-aliasing. */ +#define stream_Downsample_state_common\ + stream_state_common;\ + /* The client sets the following before initialization. */\ + int Colors;\ + int Columns; /* # of input columns */\ + int XFactor, YFactor;\ + bool AntiAlias;\ + bool padX, padY; /* keep excess samples */\ + /* The following are updated dynamically. */\ + int x, y /* position within input image */ +#define s_Downsample_set_defaults_inline(ss)\ + ((ss)->AntiAlias = (ss)->padX = (ss)->padY = false) +typedef struct stream_Downsample_state_s { + stream_Downsample_state_common; +} stream_Downsample_state; + +/* Subsample */ +/****** Subsample DOESN'T IMPLEMENT padY YET ******/ +typedef struct stream_Subsample_state_s { + stream_Downsample_state_common; +} stream_Subsample_state; +extern const stream_template s_Subsample_template; + +/* Average */ +typedef struct stream_Average_state_s { + stream_Downsample_state_common; + uint sum_size; + uint copy_size; + uint *sums; /* accumulated sums for average */ +} stream_Average_state; + +#define private_st_Average_state() /* in gdevpsds.c */\ + gs_private_st_ptrs1(st_Average_state, stream_Average_state,\ + "stream_Average_state", avg_enum_ptrs, avg_reloc_ptrs, sums) +extern const stream_template s_Average_template; + +#endif /* gdevpsds_INCLUDED */ diff --git a/pstoraster/gdevpstr.c b/pstoraster/gdevpstr.c new file mode 100644 index 0000000000..48f5780d3f --- /dev/null +++ b/pstoraster/gdevpstr.c @@ -0,0 +1,197 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Stream output for PostScript- and PDF-writing drivers */ +#include "math_.h" /* for fabs */ +#include "stdio_.h" /* for stream.h */ +#include "string_.h" /* for strchr */ +#include "gdevpstr.h" +#include "stream.h" + +/* ------ Output ------ */ + +/* Put a byte array on a stream. */ +int +pwrite(stream * s, const void *ptr, uint count) +{ + uint used; + + sputs(s, (const byte *)ptr, count, &used); + return (int)used; +} + +/* Put a string on a stream. */ +int +pputs(stream * s, const char *str) +{ + uint len = strlen(str); + uint used; + int status = sputs(s, (const byte *)str, len, &used); + + return (status >= 0 && used == len ? 0 : EOF); +} + +/* Print a format string up to the first variable substitution. */ +/* Return a pointer to the %, or to the terminating 0 if no % found. */ +private const char * +pprintf_scan(stream * s, const char *format) +{ + const char *fp = format; + + for (; *fp != 0; ++fp) { + if (*fp == '%') { + if (fp[1] != '%') + break; + ++fp; + } + sputc(s, *fp); + } + return fp; +} + +/* Print (an) int value(s) using a format. */ +const char * +pprintd1(stream * s, const char *format, int v) +{ + const char *fp = pprintf_scan(s, format); + char str[25]; + +#ifdef DEBUG + if (*fp == 0 || fp[1] != 'd') /* shouldn't happen! */ + lprintf1("Bad format in pprintd1: %s\n", format); +#endif + sprintf(str, "%d", v); + pputs(s, str); + return pprintf_scan(s, fp + 2); +} +const char * +pprintd2(stream * s, const char *format, int v1, int v2) +{ + return pprintd1(s, pprintd1(s, format, v1), v2); +} +const char * +pprintd3(stream * s, const char *format, int v1, int v2, int v3) +{ + return pprintd2(s, pprintd1(s, format, v1), v2, v3); +} +const char * +pprintd4(stream * s, const char *format, int v1, int v2, int v3, int v4) +{ + return pprintd2(s, pprintd2(s, format, v1, v2), v3, v4); +} + +/* Print (a) floating point number(s) using a format. */ +/* See gdevpdfx.h for why this is needed. */ +const char * +pprintg1(stream * s, const char *format, floatp v) +{ + const char *fp = pprintf_scan(s, format); + char str[50]; + +#ifdef DEBUG + if (*fp == 0 || fp[1] != 'g') /* shouldn't happen! */ + lprintf1("Bad format in pprintg: %s\n", format); +#endif + sprintf(str, "%g", v); + if (strchr(str, 'e')) { + /* Bad news. Try again using f-format. */ + sprintf(str, (fabs(v) > 1 ? "%1.1f" : "%1.8f"), v); + } + pputs(s, str); + return pprintf_scan(s, fp + 2); +} +const char * +pprintg2(stream * s, const char *format, floatp v1, floatp v2) +{ + return pprintg1(s, pprintg1(s, format, v1), v2); +} +const char * +pprintg3(stream * s, const char *format, floatp v1, floatp v2, floatp v3) +{ + return pprintg2(s, pprintg1(s, format, v1), v2, v3); +} +const char * +pprintg4(stream * s, const char *format, floatp v1, floatp v2, floatp v3, + floatp v4) +{ + return pprintg2(s, pprintg2(s, format, v1, v2), v3, v4); +} +const char * +pprintg6(stream * s, const char *format, floatp v1, floatp v2, floatp v3, + floatp v4, floatp v5, floatp v6) +{ + return pprintg3(s, pprintg3(s, format, v1, v2, v3), v4, v5, v6); +} + +/* Print a long value using a format. */ +const char * +pprintld1(stream * s, const char *format, long v) +{ + const char *fp = pprintf_scan(s, format); + char str[25]; + +#ifdef DEBUG + if (*fp == 0 || fp[1] != 'l' || fp[2] != 'd') /* shouldn't happen! */ + lprintf1("Bad format in pprintld: %s\n", format); +#endif + sprintf(str, "%ld", v); + pputs(s, str); + return pprintf_scan(s, fp + 3); +} +const char * +pprintld2(stream * s, const char *format, long v1, long v2) +{ + return pprintld1(s, pprintld1(s, format, v1), v2); +} +const char * +pprintld3(stream * s, const char *format, long v1, long v2, long v3) +{ + return pprintld2(s, pprintld1(s, format, v1), v2, v3); +} + +/* Print (a) string(s) using a format. */ +const char * +pprints1(stream * s, const char *format, const char *str) +{ + const char *fp = pprintf_scan(s, format); + +#ifdef DEBUG + if (*fp == 0 || fp[1] != 's') /* shouldn't happen! */ + lprintf1("Bad format in pprints: %s\n", format); +#endif + pputs(s, str); + return pprintf_scan(s, fp + 2); +} +const char * +pprints2(stream * s, const char *format, const char *str1, const char *str2) +{ + return pprints1(s, pprints1(s, format, str1), str2); +} +const char * +pprints3(stream * s, const char *format, const char *str1, const char *str2, + const char *str3) +{ + return pprints2(s, pprints1(s, format, str1), str2, str3); +} diff --git a/pstoraster/gdevpstr.h b/pstoraster/gdevpstr.h new file mode 100644 index 0000000000..12156c39ad --- /dev/null +++ b/pstoraster/gdevpstr.h @@ -0,0 +1,90 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Stream output for PostScript- and PDF-writing drivers. */ + +#ifndef gdevpstr_INCLUDED +# define gdevpstr_INCLUDED + +/* Define an opaque type for streams. */ +#ifndef stream_DEFINED +# define stream_DEFINED +typedef struct stream_s stream; + +#endif + +/* Put a character on a stream. */ +#define pputc(s, c) spputc(s, c) + +/* Put a byte array on a stream. */ +int pwrite(P3(stream * s, const void *ptr, uint count)); + +/* Put a string on a stream. */ +int pputs(P2(stream * s, const char *str)); + +/* + * Print (a) floating point number(s) using a format. This is needed + * because %f format always prints a fixed number of digits after the + * decimal point, and %g format may use %e format, which PDF disallows. + * These functions return a pointer to the next %-element of the format, or + * to the terminating 0. + */ +const char *pprintg1(P3(stream * s, const char *format, floatp v)); +const char *pprintg2(P4(stream * s, const char *format, floatp v1, floatp v2)); +const char *pprintg3(P5(stream * s, const char *format, + floatp v1, floatp v2, floatp v3)); +const char *pprintg4(P6(stream * s, const char *format, + floatp v1, floatp v2, floatp v3, floatp v4)); +const char *pprintg6(P8(stream * s, const char *format, + floatp v1, floatp v2, floatp v3, floatp v4, + floatp v5, floatp v6)); + +/* + * The rest of these printing functions exist solely because the ANSI C + * "standard" for functions with a variable number of arguments is not + * implemented properly or consistently across compilers. + */ +/* Print (an) int value(s) using a format. */ +const char *pprintd1(P3(stream * s, const char *format, int v)); +const char *pprintd2(P4(stream * s, const char *format, int v1, int v2)); +const char *pprintd3(P5(stream * s, const char *format, + int v1, int v2, int v3)); +const char *pprintd4(P6(stream * s, const char *format, + int v1, int v2, int v3, int v4)); + +/* Print a long value using a format. */ +const char *pprintld1(P3(stream * s, const char *format, long v)); +const char *pprintld2(P4(stream * s, const char *format, long v1, long v2)); +const char *pprintld3(P5(stream * s, const char *format, + long v1, long v2, long v3)); + +/* Print (a) string(s) using a format. */ +const char *pprints1(P3(stream * s, const char *format, const char *str)); +const char *pprints2(P4(stream * s, const char *format, + const char *str1, const char *str2)); +const char *pprints3(P5(stream * s, const char *format, + const char *str1, const char *str2, const char *str3)); + +#endif /* gdevpstr_INCLUDED */ diff --git a/pstoraster/gdevpxat.h b/pstoraster/gdevpxat.h new file mode 100644 index 0000000000..bca49fa720 --- /dev/null +++ b/pstoraster/gdevpxat.h @@ -0,0 +1,149 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Attribute ID definitions for PCL XL */ + +#ifndef gdevpxat_INCLUDED +# define gdevpxat_INCLUDED + +typedef enum { + + pxaPaletteDepth = 2, + pxaColorSpace, + pxaNullBrush, + pxaNullPen, + pxaPaletteData, + + pxaPatternSelectID = 8, + pxaGrayLevel, + pxaLightness, /* 2.0 */ + pxaRGBColor, + pxaPatternOrigin, + pxaNewDestinationSize, + pxaPrimaryArray, /* 2.0 */ + pxaPrimaryDepth, /* 2.0 */ + pxaSaturation, /* 2.0 */ + pxaColorimetricColorSpace, /* 2.0 */ + pxaXYChromaticities, /* 2.0 */ + pxaWhiteReferencePoint, /* 2.0 */ + pxaCRGBMinMax, /* 2.0 */ + pxaGammaGain, /* 2.0 */ + + pxaDeviceMatrix = 33, + pxaDitherMatrixDataType, + pxaDitherOrigin, + pxaMediaDestination, + pxaMediaSize, + pxaMediaSource, + pxaMediaType, + pxaOrientation, + pxaPageAngle, + pxaPageOrigin, + pxaPageScale, + pxaROP3, + pxaTxMode, + + pxaCustomMediaSize = 47, + pxaCustomMediaSizeUnits, + pxaPageCopies, + pxaDitherMatrixSize, + pxaDitherMatrixDepth, + pxaSimplexPageMode, + pxaDuplexPageMode, + pxaDuplexPageSide, + + pxaArcDirection = 65, + pxaBoundingBox, + pxaDashOffset, + pxaEllipseDimension, + pxaEndPoint, + pxaFillMode, + pxaLineCapStyle, + pxaLineJoinStyle, + pxaMiterLength, + pxaLineDashStyle, + pxaPenWidth, + pxaPoint, + pxaNumberOfPoints, + pxaSolidLine, + pxaStartPoint, + pxaPointType, + pxaControlPoint1, + pxaControlPoint2, + pxaClipRegion, + pxaClipMode, + + pxaColorDepth = 98, + pxaBlockHeight, + pxaColorMapping, + pxaCompressMode, + pxaDestinationBox, + pxaDestinationSize, + pxaPatternPersistence, + pxaPatternDefineID, + + pxaSourceHeight = 107, + pxaSourceWidth, + pxaStartLine, + pxaPadBytesMultiple, /* 2.0 */ + pxaBlockByteLength, /* 2.0 */ + + pxaNumberOfScanLines = 115, + + pxaCommentData = 129, + pxaDataOrg, + + pxaMeasure = 134, + + pxaSourceType = 136, + pxaUnitsPerMeasure, + + pxaStreamName = 139, + pxaStreamDataLength, + + pxaErrorReport = 143, + + pxaCharAngle = 161, + pxaCharCode, + pxaCharDataSize, + pxaCharScale, + pxaCharShear, + pxaCharSize, + pxaFontHeaderLength, + pxaFontName, + pxaFontFormat, + pxaSymbolSet, + pxaTextData, + pxaCharSubModeArray, + + pxaXSpacingData = 175, + pxaYSpacingData, + pxaCharBoldValue, + + px_attribute_next + +} px_attribute_t; + +#endif /* gdevpxat_INCLUDED */ diff --git a/pstoraster/gdevpxen.h b/pstoraster/gdevpxen.h new file mode 100644 index 0000000000..25eb1e30cc --- /dev/null +++ b/pstoraster/gdevpxen.h @@ -0,0 +1,269 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Enumerated attribute value definitions for PCL XL */ + +#ifndef gdevpxen_INCLUDED +# define gdevpxen_INCLUDED + +typedef enum { + eClockWise = 0, + eCounterClockWise, + pxeArcDirection_next +} pxeArcDirection_t; + +typedef enum { + eNoSubstitution = 0, + eVerticalSubstitution, + pxeCharSubModeArray_next +} pxeCharSubModeArray_t; + +typedef enum { + eNonZeroWinding = 0, + eEvenOdd, + pxeClipMode_next, + pxeFillMode_next = pxeClipMode_next /* see pxeFillMode_t below */ +} pxeClipMode_t; + +typedef enum { + eInterior = 0, + eExterior, + pxeClipRegion_next +} pxeClipRegion_t; + +typedef enum { + e1Bit = 0, + e4Bit, + e8Bit, + pxeColorDepth_next +} pxeColorDepth_t; + +typedef enum { + eCRGB = 5, /* Note: for this enumeration, 0 is not a valid value */ + pxeColorimetricColorSpace_next +} pxeColorimetricColorSpace_t; /* 2.0 */ + +typedef enum { + eDirectPixel = 0, + eIndexedPixel, + pxeColorMapping_next +} pxeColorMapping_t; + +typedef enum { + eNoColorSpace = 0, /* Note: for this enumeration, 0 is not a valid value */ + eGray, + eRGB, + eSRGB, /* 2.0 */ + pxeColorSpace_next +} pxeColorSpace_t; + +typedef enum { + eNoCompression = 0, + eRLECompression, + eJPEGCompression, /* 2.0 */ + pxeCompressMode_next +} pxeCompressMode_t; + +typedef enum { + eBinaryHighByteFirst = 0, + eBinaryLowByteFirst, + pxeDataOrg_next /* is this DataOrg or DataOrganization? */ +} pxeDataOrg_t; + +typedef enum { + eDefault = 0, /* bad choice of name! */ + pxeDataSource_next +} pxeDataSource_t; + +typedef enum { + eUByte = 0, + eSByte, + eUInt16, + eSInt16, + pxeDataType_next +} pxeDataType_t; + +typedef enum { + eDownloaded = -1, /* Not a real value, indicates a downloaded matrix */ + eDeviceBest = 0, + pxeDitherMatrix_next +} pxeDitherMatrix_t; + +typedef enum { + eDuplexHorizontalBinding = 0, + eDuplexVerticalBinding, + pxeDuplexPageMode_next +} pxeDuplexPageMode_t; + +typedef enum { + eFrontMediaSide = 0, + eBackMediaSide, + pxeDuplexPageSide_next +} pxeDuplexPageSide_t; + +typedef enum { + /* Several pieces of code know that this is a bit mask. */ + eNoReporting = 0, + eBackChannel, + eErrorPage, + eBackChAndErrPage, + eNWBackChannel, /* 2.0 */ + eNWErrorPage, /* 2.0 */ + eNWBackChAndErrPage, /* 2.0 */ + pxeErrorReport_next +} pxeErrorReport_t; + +typedef pxeClipMode_t pxeFillMode_t; + +typedef enum { + eButtCap = 0, + eRoundCap, + eSquareCap, + eTriangleCap, + pxeLineCap_next +} pxeLineCap_t; + +#define pxeLineCap_to_library\ + { gs_cap_butt, gs_cap_round, gs_cap_square, gs_cap_triangle } + +typedef enum { + eMiterJoin = 0, + eRoundJoin, + eBevelJoin, + eNoJoin, + pxeLineJoin_next +} pxeLineJoin_t; + +#define pxeLineJoin_to_library\ + { gs_join_miter, gs_join_round, gs_join_bevel, gs_join_none } + +typedef enum { + eInch = 0, + eMillimeter, + eTenthsOfAMillimeter, + pxeMeasure_next +} pxeMeasure_t; + +#define pxeMeasure_to_points { 72.0, 72.0 / 25.4, 72.0 / 254.0 } + +typedef enum { + eDefaultDestination = 0, + eFaceDownBin, /* 2.0 */ + eFaceUpBin, /* 2.0 */ + eJobOffsetBin, /* 2.0 */ + pxeMediaDestination_next +} pxeMediaDestination_t; + +typedef enum { + eLetterPaper = 0, + eLegalPaper, + eA4Paper, + eExecPaper, + eLedgerPaper, + eA3Paper, + eCOM10Envelope, + eMonarchEnvelope, + eC5Envelope, + eDLEnvelope, + eJB4Paper, + eJB5Paper, + eB5Envelope, + eJPostcard, + eJDoublePostcard, + eA5Paper, + eA6Paper, /* 2.0 */ + eJB6Paper, /* 2.0 */ + pxeMediaSize_next +} pxeMediaSize_t; + +/* + * Apply a macro (or procedure) to all known paper sizes. + * The arguments are: + * media size code, resolution for width/height, width, height. + */ +#define px_enumerate_media(m)\ + m(eLetterPaper, 300, 2550, 3300)\ + m(eLegalPaper, 300, 2550, 5300)\ + m(eA4Paper, 300, 2480, 3507)\ + m(eExecPaper, 300, 2175, 3150)\ + m(eLedgerPaper, 300, 3300, 5100)\ + m(eA3Paper, 300, 3507, 4960)\ + m(eCOM10Envelope, 300, 1237, 2850)\ + m(eMonarchEnvelope, 300, 1162, 2250)\ + m(eC5Envelope, 300, 1913, 2704)\ + m(eDLEnvelope, 300, 1299, 2598)\ + m(eB5Envelope, 300, 2078, 2952) + +typedef enum { + eDefaultSource = 0, + eAutoSelect, + eManualFeed, + eMultiPurposeTray, + eUpperCassette, + eLowerCassette, + eEnvelopeTray, + eThirdCassette, /* 2.0 */ + pxeMediaSource_next +} pxeMediaSource_t; + +/**** MediaType is not documented. ****/ +typedef enum { + eDefaultType = 0, + pxeMediaType_next +} pxeMediaType_t; + +typedef enum { + ePortraitOrientation = 0, + eLandscapeOrientation, + eReversePortrait, + eReverseLandscape, + pxeOrientation_next +} pxeOrientation_t; + +typedef enum { + eTempPattern = 0, + ePagePattern, + eSessionPattern, + pxePatternPersistence_next +} pxePatternPersistence_t; + +typedef enum { + eSimplexFrontSide = 0, + pxeSimplexPageMode_next +} pxeSimplexPageMode_t; + +typedef enum { + eOpaque = 0, + eTransparent, + pxeTxMode_next +} pxeTxMode_t; + +typedef enum { + eHorizontal = 0, + eVertical, + pxeWritingMode_next +} pxeWritingMode_t; /* 2.0 */ + +#endif /* gdevpxen_INCLUDED */ diff --git a/pstoraster/gdevpxop.h b/pstoraster/gdevpxop.h new file mode 100644 index 0000000000..9b61a01e0a --- /dev/null +++ b/pstoraster/gdevpxop.h @@ -0,0 +1,114 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Operator and other tag definitions for PCL XL */ + +#ifndef gdevpxop_INCLUDED +# define gdevpxop_INCLUDED + +typedef enum { +/*0x */ + pxtNull = 0x00, pxt01, pxt02, pxt03, + pxt04, pxt05, pxt06, pxt07, + pxt08, pxtHT, pxtLF, pxtVT, + pxtFF, pxtCR, pxt0e, pxt0f, +/*1x */ + pxt10, pxt11, pxt12, pxt13, + pxt14, pxt15, pxt16, pxt17, + pxt18, pxt19, pxt1a, pxt1b, + pxt1c, pxt1d, pxt1e, pxt1f, +/*2x */ + pxtSpace, pxt21, pxt22, pxt23, + pxt24, pxt25, pxt26, pxt_beginASCII, + pxt_beginBinaryMSB, pxt_beginBinaryLSB, pxt2a, pxt2b, + pxt2c, pxt2d, pxt2e, pxt2f, +/*3x */ + pxt30, pxt31, pxt32, pxt33, + pxt34, pxt35, pxt36, pxt37, + pxt38, pxt39, pxt3a, pxt3b, + pxt3c, pxt3d, pxt3e, pxt3f, +/*4x */ + pxt40, pxtBeginSession, pxtEndSession, pxtBeginPage, + pxtEndPage, pxt45, pxt46, pxtComment, + pxtOpenDataSource, pxtCloseDataSource, pxt4a, pxt4b, + pxt4c, pxt4d, pxt4e, pxtBeginFontHeader, +/*5x */ + pxtReadFontHeader, pxtEndFontHeader, pxtBeginChar, pxtReadChar, + pxtEndChar, pxtRemoveFont, pxtSetCharAttributes /*2.0 */ , pxt57, + pxt58, pxt59, pxt5a, pxtBeginStream, + pxtReadStream, pxtEndStream, pxtExecStream, pxtRemoveStream /*2.0 */ , +/*6x */ + pxtPopGS, pxtPushGS, pxtSetClipReplace, pxtSetBrushSource, + pxtSetCharAngle, pxtSetCharScale, pxtSetCharShear, pxtSetClipIntersect, + pxtSetClipRectangle, pxtSetClipToPage, pxtSetColorSpace, pxtSetCursor, + pxtSetCursorRel, pxtSetHalftoneMethod, pxtSetFillMode, pxtSetFont, +/*7x */ + pxtSetLineDash, pxtSetLineCap, pxtSetLineJoin, pxtSetMiterLimit, + pxtSetPageDefaultCTM, pxtSetPageOrigin, pxtSetPageRotation, pxtSetPageScale, + pxtSetPaintTxMode, pxtSetPenSource, pxtSetPenWidth, pxtSetROP, + pxtSetSourceTxMode, pxtSetCharBoldValue, pxt7e, pxtSetClipMode, +/*8x */ + pxtSetPathToClip, pxtSetCharSubMode, pxt82, pxt83, + pxtCloseSubPath, pxtNewPath, pxtPaintPath, pxt87, + pxt88, pxt89, pxt8a, pxt8b, + pxt8c, pxt8d, pxt8e, pxt8f, +/*9x */ + pxt90, pxtArcPath, pxt92, pxtBezierPath, + pxt94, pxtBezierRelPath, pxtChord, pxtChordPath, + pxtEllipse, pxtEllipsePath, pxt9a, pxtLinePath, + pxt9c, pxtLineRelPath, pxtPie, pxtPiePath, +/*ax */ + pxtRectangle, pxtRectanglePath, pxtRoundRectangle, pxtRoundRectanglePath, + pxta4, pxta5, pxta6, pxta7, + pxtText, pxtTextPath, pxtaa, pxtab, + pxtac, pxtad, pxtae, pxtaf, +/*bx */ + pxtBeginImage, pxtReadImage, pxtEndImage, pxtBeginRastPattern, + pxtReadRastPattern, pxtEndRastPattern, pxtBeginScan, pxtb7, + pxtEndScan, pxtScanLineRel, pxtba, pxtbb, + pxtbc, pxtbd, pxtbe, pxtbf, +/*cx */ + pxt_ubyte, pxt_uint16, pxt_uint32, pxt_sint16, + pxt_sint32, pxt_real32, pxtc6, pxtc7, + pxt_ubyte_array, pxt_uint16_array, pxt_uint32_array, pxt_sint16_array, + pxt_sint32_array, pxt_real32_array, pxtce, pxtcf, +/*dx */ + pxt_ubyte_xy, pxt_uint16_xy, pxt_uint32_xy, pxt_sint16_xy, + pxt_sint32_xy, pxt_real32_xy, pxtd6, pxtd7, + pxtd8, pxtd9, pxtda, pxtdb, + pxtdc, pxtdd, pxtde, pxtdf, +/*ex */ + pxt_ubyte_box, pxt_uint16_box, pxt_uint32_box, pxt_sint16_box, + pxt_sint32_box, pxt_real32_box, pxte6, pxte7, + pxte8, pxte9, pxtea, pxteb, + pxtec, pxted, pxtee, pxtef, +/*fx */ + pxtf0, pxtf1, pxtf2, pxtf3, + pxtf4, pxtf5, pxtf6, pxtf7, + pxt_attr_ubyte, pxt_attr_uint16, pxt_dataLength, pxt_dataLengthByte, + pxtfc, pxtfd, pxtfe, pxtff +} px_tag_t; + +#endif /* gdevpxop_INCLUDED */ diff --git a/pstoraster/gdevvec.c b/pstoraster/gdevvec.c new file mode 100644 index 0000000000..80adbb7e84 --- /dev/null +++ b/pstoraster/gdevvec.c @@ -0,0 +1,905 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Utilities for "vector" devices */ +#include "math_.h" +#include "memory_.h" +#include "string_.h" +#include "gx.h" +#include "gp.h" +#include "gserrors.h" +#include "gsparam.h" +#include "gsutil.h" +#include "gxfixed.h" +#include "gdevvec.h" +#include "gscspace.h" +#include "gxdcolor.h" +#include "gxpaint.h" /* requires gx_path, ... */ +#include "gzpath.h" +#include "gzcpath.h" + +/****** + ****** NOTE: EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE. + ****** USE AT YOUR OWN RISK. + ******/ + +/* Structure descriptors */ +public_st_device_vector(); +public_st_vector_image_enum(); + +/* ================ Default implementations of vector procs ================ */ + +int +gdev_vector_setflat(gx_device_vector * vdev, floatp flatness) +{ + return 0; +} + +int +gdev_vector_dopath(gx_device_vector * vdev, const gx_path * ppath, + gx_path_type_t type) +{ + bool do_close = (type & gx_path_type_stroke) != 0; + gs_fixed_rect rect; + gs_point scale; + double x_start = 0, y_start = 0, x_prev, y_prev; + bool first = true; + gs_path_enum cenum; + int code; + + if (gx_path_is_rectangle(ppath, &rect)) + return (*vdev_proc(vdev, dorect)) (vdev, rect.p.x, rect.p.y, rect.q.x, + rect.q.y, type); + scale = vdev->scale; + code = (*vdev_proc(vdev, beginpath)) (vdev, type); + gx_path_enum_init(&cenum, ppath); + for (;;) { + fixed vs[6]; + int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs); + double x, y; + + sw:switch (pe_op) { + case 0: /* done */ + return (*vdev_proc(vdev, endpath)) (vdev, type); + case gs_pe_moveto: + code = (*vdev_proc(vdev, moveto)) + (vdev, x_prev, y_prev, (x = fixed2float(vs[0]) / scale.x), + (y = fixed2float(vs[1]) / scale.y), type); + if (first) + x_start = x, y_start = y, first = false; + break; + case gs_pe_lineto: + code = (*vdev_proc(vdev, lineto)) + (vdev, x_prev, y_prev, (x = fixed2float(vs[0]) / scale.x), + (y = fixed2float(vs[1]) / scale.y), type); + break; + case gs_pe_curveto: + code = (*vdev_proc(vdev, curveto)) + (vdev, x_prev, y_prev, + fixed2float(vs[0]) / scale.x, + fixed2float(vs[1]) / scale.y, + fixed2float(vs[2]) / scale.x, + fixed2float(vs[3]) / scale.y, + (x = fixed2float(vs[4]) / scale.x), + (y = fixed2float(vs[5]) / scale.y), + type); + break; + case gs_pe_closepath: + x = x_start, y = y_start; + if (do_close) { + code = (*vdev_proc(vdev, closepath)) + (vdev, x_prev, y_prev, x_start, y_start, type); + break; + } + pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *) vs); + if (pe_op != 0) { + code = (*vdev_proc(vdev, closepath)) + (vdev, x_prev, y_prev, x_start, y_start, type); + if (code < 0) + return code; + goto sw; + } + return (*vdev_proc(vdev, endpath)) (vdev, type); + default: /* can't happen */ + return_error(gs_error_unknownerror); + } + if (code < 0) + return code; + x_prev = x, y_prev = y; + } +} + +int +gdev_vector_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, + fixed y1, gx_path_type_t type) +{ + int code = (*vdev_proc(vdev, beginpath)) (vdev, type); + + if (code < 0) + return code; + code = gdev_vector_write_rectangle(vdev, x0, y0, x1, y1, + (type & gx_path_type_stroke) != 0, + gx_rect_x_first); + if (code < 0) + return code; + return (*vdev_proc(vdev, endpath)) (vdev, type); +} + +/* ================ Utility procedures ================ */ + +/* Recompute the cached color values. */ +private void +gdev_vector_load_cache(gx_device_vector * vdev) +{ + vdev->black = gx_device_black((gx_device *)vdev); + vdev->white = gx_device_white((gx_device *)vdev); +} + +/* Initialize the state. */ +void +gdev_vector_init(gx_device_vector * vdev) +{ + gdev_vector_reset(vdev); + vdev->scale.x = vdev->scale.y = 1.0; + vdev->in_page = false; + gdev_vector_load_cache(vdev); +} + +/* Reset the remembered graphics state. */ +void +gdev_vector_reset(gx_device_vector * vdev) +{ + static const gs_imager_state state_initial = + {gs_imager_state_initial(1)}; + + vdev->state = state_initial; + color_unset(&vdev->fill_color); + color_unset(&vdev->stroke_color); + vdev->clip_path_id = + vdev->no_clip_path_id = gs_next_ids(1); +} + +/* Open the output file and stream. */ +int +gdev_vector_open_file_bbox(gx_device_vector * vdev, uint strmbuf_size, + bool bbox) +{ /* Open the file as positionable if possible. */ + int code = gx_device_open_output_file((gx_device *) vdev, vdev->fname, + true, true, &vdev->file); + + if (code < 0) + return code; + if ((vdev->strmbuf = gs_alloc_bytes(vdev->v_memory, strmbuf_size, + "vector_open(strmbuf)")) == 0 || + (vdev->strm = s_alloc(vdev->v_memory, + "vector_open(strm)")) == 0 || + (bbox && + (vdev->bbox_device = + gs_alloc_struct_immovable(vdev->v_memory, + gx_device_bbox, &st_device_bbox, + "vector_open(bbox_device)")) == 0) + ) { + if (vdev->bbox_device) + gs_free_object(vdev->v_memory, vdev->bbox_device, + "vector_open(bbox_device)"); + vdev->bbox_device = 0; + if (vdev->strm) + gs_free_object(vdev->v_memory, vdev->strm, + "vector_open(strm)"); + vdev->strm = 0; + if (vdev->strmbuf) + gs_free_object(vdev->v_memory, vdev->strmbuf, + "vector_open(strmbuf)"); + vdev->strmbuf = 0; + fclose(vdev->file); + vdev->file = 0; + return_error(gs_error_VMerror); + } + vdev->strmbuf_size = strmbuf_size; + swrite_file(vdev->strm, vdev->file, vdev->strmbuf, strmbuf_size); + /* + * We don't want finalization to close the file, but we do want it + * to flush the stream buffer. + */ + vdev->strm->procs.close = vdev->strm->procs.flush; + if (vdev->bbox_device) { + gx_device_bbox_init(vdev->bbox_device, NULL); + gx_device_set_resolution((gx_device *) vdev->bbox_device, + vdev->HWResolution[0], + vdev->HWResolution[1]); + /* Do the right thing about upright vs. inverted. */ + /* (This is dangerous in general, since the procedure */ + /* might reference non-standard elements.) */ + set_dev_proc(vdev->bbox_device, get_initial_matrix, + dev_proc(vdev, get_initial_matrix)); + (*dev_proc(vdev->bbox_device, open_device)) + ((gx_device *) vdev->bbox_device); + } + return 0; +} + +/* Get the current stream, calling beginpage if in_page is false. */ +stream * +gdev_vector_stream(gx_device_vector * vdev) +{ + if (!vdev->in_page) { + (*vdev_proc(vdev, beginpage)) (vdev); + vdev->in_page = true; + } + return vdev->strm; +} + +/* Compare two drawing colors. */ +/* Right now we don't attempt to handle non-pure colors. */ +private bool +drawing_color_eq(const gx_drawing_color * pdc1, const gx_drawing_color * pdc2) +{ + return (gx_dc_is_pure(pdc1) ? + gx_dc_is_pure(pdc2) && + gx_dc_pure_color(pdc1) == gx_dc_pure_color(pdc2) : + gx_dc_is_null(pdc1) ? + gx_dc_is_null(pdc2) : + false); +} + +/* Update the logical operation. */ +int +gdev_vector_update_log_op(gx_device_vector * vdev, gs_logical_operation_t lop) +{ + gs_logical_operation_t diff = lop ^ vdev->state.log_op; + + if (diff != 0) { + int code = (*vdev_proc(vdev, setlogop)) (vdev, lop, diff); + + if (code < 0) + return code; + vdev->state.log_op = lop; + } + return 0; +} + +/* Update the fill color. */ +int +gdev_vector_update_fill_color(gx_device_vector * vdev, + const gx_drawing_color * pdcolor) +{ + if (!drawing_color_eq(pdcolor, &vdev->fill_color)) { + int code = (*vdev_proc(vdev, setfillcolor)) (vdev, pdcolor); + + if (code < 0) + return code; + vdev->fill_color = *pdcolor; + } + return 0; +} + +/* Update the state for filling a region. */ +private int +update_fill(gx_device_vector * vdev, const gx_drawing_color * pdcolor, + gs_logical_operation_t lop) +{ + int code = gdev_vector_update_fill_color(vdev, pdcolor); + + if (code < 0) + return code; + return gdev_vector_update_log_op(vdev, lop); +} + +/* Bring state up to date for filling. */ +int +gdev_vector_prepare_fill(gx_device_vector * vdev, const gs_imager_state * pis, + const gx_fill_params * params, const gx_drawing_color * pdcolor) +{ + if (params->flatness != vdev->state.flatness) { + int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness); + + if (code < 0) + return code; + vdev->state.flatness = params->flatness; + } + return update_fill(vdev, pdcolor, pis->log_op); +} + +/* Compare two dash patterns. */ +private bool +dash_pattern_eq(const float *stored, const gx_dash_params * set, floatp scale) +{ + int i; + + for (i = 0; i < set->pattern_size; ++i) + if (stored[i] != (float)(set->pattern[i] * scale)) + return false; + return true; +} + +/* Bring state up to date for stroking. */ +int +gdev_vector_prepare_stroke(gx_device_vector * vdev, const gs_imager_state * pis, + const gx_stroke_params * params, const gx_drawing_color * pdcolor, + floatp scale) +{ + int pattern_size = pis->line_params.dash.pattern_size; + float dash_offset = pis->line_params.dash.offset * scale; + float half_width = pis->line_params.half_width * scale; + + if (pattern_size > max_dash) + return_error(gs_error_limitcheck); + if (dash_offset != vdev->state.line_params.dash.offset || + pattern_size != vdev->state.line_params.dash.pattern_size || + (pattern_size != 0 && + !dash_pattern_eq(vdev->dash_pattern, &pis->line_params.dash, + scale)) + ) { + float pattern[max_dash]; + int i, code; + + for (i = 0; i < pattern_size; ++i) + pattern[i] = pis->line_params.dash.pattern[i] * scale; + code = (*vdev_proc(vdev, setdash)) + (vdev, pattern, pattern_size, dash_offset); + if (code < 0) + return code; + memcpy(vdev->dash_pattern, pattern, pattern_size * sizeof(float)); + + vdev->state.line_params.dash.pattern_size = pattern_size; + vdev->state.line_params.dash.offset = dash_offset; + } + if (params->flatness != vdev->state.flatness) { + int code = (*vdev_proc(vdev, setflat)) (vdev, params->flatness); + + if (code < 0) + return code; + vdev->state.flatness = params->flatness; + } + if (half_width != vdev->state.line_params.half_width) { + int code = (*vdev_proc(vdev, setlinewidth)) + (vdev, pis->line_params.half_width * 2); + + if (code < 0) + return code; + vdev->state.line_params.half_width = half_width; + } + if (pis->line_params.miter_limit != vdev->state.line_params.miter_limit) { + int code = (*vdev_proc(vdev, setmiterlimit)) + (vdev, pis->line_params.miter_limit); + + if (code < 0) + return code; + gx_set_miter_limit(&vdev->state.line_params, + pis->line_params.miter_limit); + } + if (pis->line_params.cap != vdev->state.line_params.cap) { + int code = (*vdev_proc(vdev, setlinecap)) + (vdev, pis->line_params.cap); + + if (code < 0) + return code; + vdev->state.line_params.cap = pis->line_params.cap; + } + if (pis->line_params.join != vdev->state.line_params.join) { + int code = (*vdev_proc(vdev, setlinejoin)) + (vdev, pis->line_params.join); + + if (code < 0) + return code; + vdev->state.line_params.join = pis->line_params.join; + } { + int code = gdev_vector_update_log_op(vdev, pis->log_op); + + if (code < 0) + return code; + } + if (!drawing_color_eq(pdcolor, &vdev->stroke_color)) { + int code = (*vdev_proc(vdev, setstrokecolor)) (vdev, pdcolor); + + if (code < 0) + return code; + vdev->stroke_color = *pdcolor; + } + return 0; +} + +/* Write a polygon as part of a path. */ +/* May call beginpath, moveto, lineto, closepath, endpath. */ +int +gdev_vector_write_polygon(gx_device_vector * vdev, const gs_fixed_point * points, + uint count, bool close, gx_path_type_t type) +{ + int code = 0; + + if (type != gx_path_type_none && + (code = (*vdev_proc(vdev, beginpath)) (vdev, type)) < 0 + ) + return code; + if (count > 0) { + double x = fixed2float(points[0].x) / vdev->scale.x, y = fixed2float(points[0].y) / vdev->scale.y; + double x_start = x, y_start = y, x_prev, y_prev; + uint i; + + code = (*vdev_proc(vdev, moveto)) + (vdev, 0.0, 0.0, x, y, type); + if (code >= 0) + for (i = 1; i < count && code >= 0; ++i) { + x_prev = x, y_prev = y; + code = (*vdev_proc(vdev, lineto)) + (vdev, x_prev, y_prev, + (x = fixed2float(points[i].x) / vdev->scale.x), + (y = fixed2float(points[i].y) / vdev->scale.y), + type); + } + if (code >= 0 && close) + code = (*vdev_proc(vdev, closepath)) + (vdev, x, y, x_start, y_start, type); + } + return (code >= 0 && type != gx_path_type_none ? + (*vdev_proc(vdev, endpath)) (vdev, type) : code); +} + +/* Write a rectangle as part of a path. */ +/* May call moveto, lineto, closepath. */ +int +gdev_vector_write_rectangle(gx_device_vector * vdev, fixed x0, fixed y0, + fixed x1, fixed y1, bool close, gx_rect_direction_t direction) +{ + gs_fixed_point points[4]; + + points[0].x = x0, points[0].y = y0; + points[2].x = x1, points[2].y = y1; + if (direction == gx_rect_x_first) + points[1].x = x1, points[1].y = y0, + points[3].x = x0, points[3].y = y1; + else + points[1].x = x0, points[1].y = y1, + points[3].x = x1, points[3].y = y0; + return gdev_vector_write_polygon(vdev, points, 4, close, + gx_path_type_none); +} + +/* Write a clipping path by calling the path procedures. */ +int +gdev_vector_write_clip_path(gx_device_vector * vdev, const gx_clip_path * pcpath) +{ + const gx_clip_rect *prect; + gx_clip_rect page_rect; + int code; + + if (pcpath == 0) { /* There's no special provision for initclip. */ + /* Write a rectangle that covers the entire page. */ + page_rect.xmin = page_rect.ymin = 0; + page_rect.xmax = vdev->width; + page_rect.ymax = vdev->height; + page_rect.next = 0; + prect = &page_rect; + } else if (pcpath->path_valid) + return (*vdev_proc(vdev, dopath)) (vdev, &pcpath->path, + gx_path_type_clip); + else { + const gx_clip_list *list = gx_cpath_list(pcpath); + + prect = list->head; + if (prect == 0) + prect = &list->single; + } + /* Write out the rectangles. */ + code = (*vdev_proc(vdev, beginpath)) (vdev, gx_path_type_clip); + for (; code >= 0 && prect != 0; prect = prect->next) + if (prect->xmax > prect->xmin && prect->ymax > prect->ymin) + code = gdev_vector_write_rectangle + (vdev, int2fixed(prect->xmin), int2fixed(prect->ymin), + int2fixed(prect->xmax), int2fixed(prect->ymax), + false, gx_rect_x_first); + if (code >= 0) + code = (*vdev_proc(vdev, endpath)) (vdev, gx_path_type_clip); + return code; +} + +/* Update the clipping path if needed. */ +int +gdev_vector_update_clip_path(gx_device_vector * vdev, + const gx_clip_path * pcpath) +{ + if (pcpath) { + if (pcpath->id != vdev->clip_path_id) { + int code = gdev_vector_write_clip_path(vdev, pcpath); + + if (code < 0) + return code; + vdev->clip_path_id = pcpath->id; + } + } else { + if (vdev->clip_path_id != vdev->no_clip_path_id) { + int code = gdev_vector_write_clip_path(vdev, NULL); + + if (code < 0) + return code; + vdev->clip_path_id = vdev->no_clip_path_id; + } + } + return 0; +} + +/* Close the output file and stream. */ +void +gdev_vector_close_file(gx_device_vector * vdev) +{ + gs_free_object(vdev->v_memory, vdev->bbox_device, + "vector_close(bbox_device)"); + vdev->bbox_device = 0; + sclose(vdev->strm); + gs_free_object(vdev->v_memory, vdev->strm, "vector_close(strm)"); + vdev->strm = 0; + gs_free_object(vdev->v_memory, vdev->strmbuf, "vector_close(strmbuf)"); + vdev->strmbuf = 0; + fclose(vdev->file); /* we prevented sclose from doing this */ + vdev->file = 0; +} + +/* ---------------- Image enumeration ---------------- */ + +/* Initialize for enumerating an image. */ +int +gdev_vector_begin_image(gx_device_vector * vdev, + const gs_imager_state * pis, const gs_image_t * pim, + gs_image_format_t format, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * mem, const gx_image_enum_procs_t * pprocs, + gdev_vector_image_enum_t * pie) +{ + const gs_color_space *pcs = pim->ColorSpace; + int num_components; + int bits_per_pixel; + int code; + + if (pim->ImageMask) + bits_per_pixel = num_components = 1; + else + num_components = gs_color_space_num_components(pcs), + bits_per_pixel = pim->BitsPerComponent; + code = gx_image_enum_common_init((gx_image_enum_common_t *) pie, + (const gs_image_common_t *)pim, + pprocs, (gx_device *) vdev, + bits_per_pixel, num_components, + format); + if (code < 0) + return code; + pie->bits_per_pixel = bits_per_pixel * num_components / + pie->num_planes; + pie->default_info = 0; + pie->bbox_info = 0; + if ((code = gdev_vector_update_log_op(vdev, pis->log_op)) < 0 || + (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 || + ((pim->ImageMask || + (pim->CombineWithColor && rop3_uses_T(pis->log_op))) && + (code = gdev_vector_update_fill_color(vdev, pdcolor)) < 0) || + (vdev->bbox_device && + (code = (*dev_proc(vdev->bbox_device, begin_image)) + ((gx_device *) vdev->bbox_device, pis, pim, format, prect, + pdcolor, pcpath, mem, &pie->bbox_info)) < 0) + ) + return code; + pie->memory = mem; + if (prect) + pie->width = prect->q.x - prect->p.x, + pie->height = prect->q.y - prect->p.y; + else + pie->width = pim->Width, pie->height = pim->Height; + pie->bits_per_row = pie->width * pie->bits_per_pixel; + pie->y = 0; + return 0; +} + +/* End an image, optionally supplying any necessary blank padding rows. */ +/* Return 0 if we used the default implementation, 1 if not. */ +int +gdev_vector_end_image(gx_device_vector * vdev, + gdev_vector_image_enum_t * pie, bool draw_last, gx_color_index pad) +{ + int code; + + if (pie->default_info) { + code = gx_default_end_image((gx_device *) vdev, pie->default_info, + draw_last); + if (code >= 0) + code = 0; + } else { /* Fill out to the full image height. */ + if (pie->y < pie->height && pad != gx_no_color_index) { + uint bytes_per_row = (pie->bits_per_row + 7) >> 3; + byte *row = gs_alloc_bytes(pie->memory, bytes_per_row, + "gdev_vector_end_image(fill)"); + + if (row == 0) + return_error(gs_error_VMerror); +/****** FILL VALUE IS WRONG ******/ + memset(row, (byte) pad, bytes_per_row); + for (; pie->y < pie->height; pie->y++) + gx_image_data((gx_image_enum_common_t *) pie, + (const byte **)&row, 0, + bytes_per_row, 1); + gs_free_object(pie->memory, row, + "gdev_vector_end_image(fill)"); + } + code = 1; + } + if (vdev->bbox_device) { + int bcode = gx_image_end(pie->bbox_info, draw_last); + + if (bcode < 0) + code = bcode; + } + gs_free_object(pie->memory, pie, "gdev_vector_end_image"); + return code; +} + +/* ================ Device procedures ================ */ + +#define vdev ((gx_device_vector *)dev) + +/* Get parameters. */ +int +gdev_vector_get_params(gx_device * dev, gs_param_list * plist) +{ + int code = gx_default_get_params(dev, plist); + int ecode; + gs_param_string ofns; + + if (code < 0) + return code; + ofns.data = (const byte *)vdev->fname, + ofns.size = strlen(vdev->fname), + ofns.persistent = false; + if ((ecode = param_write_string(plist, "OutputFile", &ofns)) < 0) + return ecode; + return code; +} + +/* Put parameters. */ +int +gdev_vector_put_params(gx_device * dev, gs_param_list * plist) +{ + int ecode = 0; + int code; + gs_param_name param_name; + gs_param_string ofns; + + switch (code = param_read_string(plist, (param_name = "OutputFile"), &ofns)) { + case 0: + if (ofns.size > fname_size) + ecode = gs_error_limitcheck; + else + break; + goto ofe; + default: + ecode = code; + ofe:param_signal_error(plist, param_name, ecode); + case 1: + ofns.data = 0; + break; + } + + if (ecode < 0) + return ecode; + { + bool open = dev->is_open; + + /* Don't let gx_default_put_params close the device. */ + dev->is_open = false; + code = gx_default_put_params(dev, plist); + dev->is_open = open; + } + if (code < 0) + return code; + + if (ofns.data != 0 && + bytes_compare(ofns.data, ofns.size, + (const byte *)vdev->fname, strlen(vdev->fname)) + ) { + memcpy(vdev->fname, ofns.data, ofns.size); + vdev->fname[ofns.size] = 0; + if (vdev->file != 0) { + gdev_vector_close_file(vdev); + return gdev_vector_open_file(vdev, vdev->strmbuf_size); + } + } + gdev_vector_load_cache(vdev); /* in case color mapping changed */ + return 0; +} + +/* ---------------- Defaults ---------------- */ + +int +gdev_vector_fill_rectangle(gx_device * dev, int x, int y, int w, int h, + gx_color_index color) +{ + gx_drawing_color dcolor; + + /* Ignore the initial fill with white. */ + if (!vdev->in_page && color == vdev->white) + return 0; + color_set_pure(&dcolor, color); + { + int code = update_fill(vdev, &dcolor, rop3_T); + + if (code < 0) + return code; + } + if (vdev->bbox_device) { + int code = (*dev_proc(vdev->bbox_device, fill_rectangle)) + ((gx_device *) vdev->bbox_device, x, y, w, h, color); + + if (code < 0) + return code; + } + return (*vdev_proc(vdev, dorect)) (vdev, int2fixed(x), int2fixed(y), + int2fixed(x + w), int2fixed(y + h), + gx_path_type_fill); +} + +int +gdev_vector_fill_path(gx_device * dev, const gs_imager_state * pis, + gx_path * ppath, const gx_fill_params * params, + const gx_device_color * pdevc, const gx_clip_path * pcpath) +{ + int code; + + if ((code = gdev_vector_prepare_fill(vdev, pis, params, pdevc)) < 0 || + (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 || + (vdev->bbox_device && + (code = (*dev_proc(vdev->bbox_device, fill_path)) + ((gx_device *) vdev->bbox_device, pis, ppath, params, + pdevc, pcpath)) < 0) || + (code = (*vdev_proc(vdev, dopath)) + (vdev, ppath, + (params->rule > 0 ? gx_path_type_even_odd : + gx_path_type_winding_number) | gx_path_type_fill)) < 0 + ) + return gx_default_fill_path(dev, pis, ppath, params, pdevc, pcpath); + return code; +} + +int +gdev_vector_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) +{ + int code; + +/****** HANDLE SCALE ******/ + if ((code = gdev_vector_prepare_stroke(vdev, pis, params, pdcolor, + dev->HWResolution[0])) < 0 || + (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 || + (vdev->bbox_device && + (code = (*dev_proc(vdev->bbox_device, stroke_path)) + ((gx_device *) vdev->bbox_device, pis, ppath, params, + pdcolor, pcpath)) < 0) || + (code = (*vdev_proc(vdev, dopath)) + (vdev, ppath, gx_path_type_stroke)) < 0 + ) + return gx_default_stroke_path(dev, pis, ppath, params, pdcolor, pcpath); + return code; +} + +int +gdev_vector_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) +{ + fixed xl = left->start.x; + fixed wl = left->end.x - xl; + fixed yl = left->start.y; + fixed hl = left->end.y - yl; + fixed xr = right->start.x; + fixed wr = right->end.x - xr; + fixed yr = right->start.y; + fixed hr = right->end.y - yr; + fixed x0l = xl + fixed_mult_quo(wl, ybot - yl, hl); + fixed x1l = xl + fixed_mult_quo(wl, ytop - yl, hl); + fixed x0r = xr + fixed_mult_quo(wr, ybot - yr, hr); + fixed x1r = xr + fixed_mult_quo(wr, ytop - yr, hr); + +#define y0 ybot +#define y1 ytop + int code = update_fill(vdev, pdevc, lop); + gs_fixed_point points[4]; + + if (code < 0) + return gx_default_fill_trapezoid(dev, left, right, ybot, ytop, + swap_axes, pdevc, lop); + if (swap_axes) + points[0].y = x0l, points[1].y = x0r, + points[0].x = points[1].x = y0, + points[2].y = x1r, points[3].y = x1l, + points[2].x = points[3].x = y1; + else + points[0].x = x0l, points[1].x = x0r, + points[0].y = points[1].y = y0, + points[2].x = x1r, points[3].x = x1l, + points[2].y = points[3].y = y1; +#undef y0 +#undef y1 + if (vdev->bbox_device) { + int code = (*dev_proc(vdev->bbox_device, fill_trapezoid)) + ((gx_device *) vdev->bbox_device, left, right, ybot, ytop, + swap_axes, pdevc, lop); + + if (code < 0) + return code; + } + return gdev_vector_write_polygon(vdev, points, 4, true, + gx_path_type_fill); +} + +int +gdev_vector_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 pax = px + ax, pay = py + ay; + int code = update_fill(vdev, pdevc, lop); + gs_fixed_point points[4]; + + if (code < 0) + return gx_default_fill_parallelogram(dev, px, py, ax, ay, bx, by, + pdevc, lop); + if (vdev->bbox_device) { + code = (*dev_proc(vdev->bbox_device, fill_parallelogram)) + ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by, + pdevc, lop); + if (code < 0) + return code; + } + points[0].x = px, points[0].y = py; + points[1].x = pax, points[0].y = pay; + points[2].x = pax + bx, points[2].y = pay + by; + points[3].x = px + bx, points[3].y = py + by; + return gdev_vector_write_polygon(vdev, points, 4, true, + gx_path_type_fill); +} + +int +gdev_vector_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) +{ + int code = update_fill(vdev, pdevc, lop); + gs_fixed_point points[3]; + + if (code < 0) + return gx_default_fill_triangle(dev, px, py, ax, ay, bx, by, + pdevc, lop); + if (vdev->bbox_device) { + code = (*dev_proc(vdev->bbox_device, fill_triangle)) + ((gx_device *) vdev->bbox_device, px, py, ax, ay, bx, by, + pdevc, lop); + if (code < 0) + return code; + } + points[0].x = px, points[0].y = py; + points[1].x = px + ax, points[1].y = py + ay; + points[2].x = px + bx, points[2].y = py + by; + return gdev_vector_write_polygon(vdev, points, 3, true, + gx_path_type_fill); +} + +#undef vdev diff --git a/pstoraster/gdevvec.h b/pstoraster/gdevvec.h new file mode 100644 index 0000000000..f4a2aebb47 --- /dev/null +++ b/pstoraster/gdevvec.h @@ -0,0 +1,349 @@ +/* Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Common definitions for "vector" devices */ + +#ifndef gdevvec_INCLUDED +# define gdevvec_INCLUDED + +#include "gp.h" /* for gp_file_name_sizeof */ +#include "gsropt.h" +#include "gxdevice.h" +#include "gdevbbox.h" +#include "gxiparam.h" +#include "gxistate.h" +#include "stream.h" + +/****** + ****** NOTE: EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE. + ****** USE AT YOUR OWN RISK. + ******/ + +/* + * "Vector" devices produce a stream of higher-level drawing commands rather + * than a raster image. (We don't like the term "vector", since the command + * vocabulary typically includes text and raster images as well as actual + * vectors, but it's widely used in the industry, and we weren't able to + * find one that read better.) Some examples of "vector" formats are PDF, + * PostScript, PCL XL, HP-GL/2 + RTL, CGM, Windows Metafile, and Macintosh + * PICT. + * + * This file extends the basic driver structure with elements likely to be + * useful to vector devices. These include: + * + * - Tracking whether any marks have been made on the page; + * + * - Keeping track of the page bounding box; + * + * - A copy of the most recently written current graphics state + * parameters; + * + * - An output stream (for drivers that compress or otherwise filter + * their output); + * + * - A vector of procedures for writing changes to the graphics state. + * + * - The ability to work with scaled output coordinate systems. + * + * We expect to add more elements and procedures as we gain more experience + * with this kind of driver. + */ + +/* ================ Types and structures ================ */ + +/* Define the abstract type for a vector device. */ +typedef struct gx_device_vector_s gx_device_vector; + +/* Define the maximum size of the output file name. */ +#define fname_size (gp_file_name_sizeof - 1) + +/* Define the longest dash pattern we can remember. */ +#define max_dash 11 + +/* + * Define procedures for writing common output elements. Not all devices + * will support all of these elements. Note that these procedures normally + * only write out commands, and don't update the driver state itself. All + * of them are optional, called only as indicated under the utility + * procedures below. + */ +typedef enum { + gx_path_type_none = 0, + /* + * All combinations of flags are legal. Multiple commands are + * executed in the order fill, stroke, clip. + */ + gx_path_type_fill = 1, + gx_path_type_stroke = 2, + gx_path_type_clip = 4, + gx_path_type_winding_number = 0, + gx_path_type_even_odd = 8, + gx_path_type_rule = gx_path_type_winding_number | gx_path_type_even_odd +} gx_path_type_t; +typedef enum { + gx_rect_x_first, + gx_rect_y_first +} gx_rect_direction_t; +typedef struct gx_device_vector_procs_s { + /* Page management */ + int (*beginpage) (P1(gx_device_vector * vdev)); + /* Imager state */ + int (*setlinewidth) (P2(gx_device_vector * vdev, floatp width)); + int (*setlinecap) (P2(gx_device_vector * vdev, gs_line_cap cap)); + int (*setlinejoin) (P2(gx_device_vector * vdev, gs_line_join join)); + int (*setmiterlimit) (P2(gx_device_vector * vdev, floatp limit)); + int (*setdash) (P4(gx_device_vector * vdev, const float *pattern, + uint count, floatp offset)); + int (*setflat) (P2(gx_device_vector * vdev, floatp flatness)); + int (*setlogop) (P3(gx_device_vector * vdev, gs_logical_operation_t lop, + gs_logical_operation_t diff)); + /* Other state */ + int (*setfillcolor) (P2(gx_device_vector * vdev, const gx_drawing_color * pdc)); + int (*setstrokecolor) (P2(gx_device_vector * vdev, const gx_drawing_color * pdc)); + /* Paths */ + /* dopath and dorect are normally defaulted */ + int (*dopath) (P3(gx_device_vector * vdev, const gx_path * ppath, + gx_path_type_t type)); + int (*dorect) (P6(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, + fixed y1, gx_path_type_t type)); + int (*beginpath) (P2(gx_device_vector * vdev, gx_path_type_t type)); + int (*moveto) (P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, gx_path_type_t type)); + int (*lineto) (P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x, floatp y, gx_path_type_t type)); + int (*curveto) (P10(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x1, floatp y1, floatp x2, floatp y2, + floatp x3, floatp y3, gx_path_type_t type)); + int (*closepath) (P6(gx_device_vector * vdev, floatp x0, floatp y0, + floatp x_start, floatp y_start, gx_path_type_t type)); + int (*endpath) (P2(gx_device_vector * vdev, gx_path_type_t type)); +} gx_device_vector_procs; + +/* Default implementations of procedures */ +/* setflat does nothing */ +int gdev_vector_setflat(P2(gx_device_vector * vdev, floatp flatness)); + +/* dopath may call dorect, beginpath, moveto/lineto/curveto/closepath, */ +/* endpath */ +int gdev_vector_dopath(P3(gx_device_vector * vdev, const gx_path * ppath, + gx_path_type_t type)); + +/* dorect may call beginpath, moveto, lineto, closepath */ +int gdev_vector_dorect(P6(gx_device_vector * vdev, fixed x0, fixed y0, + fixed x1, fixed y1, gx_path_type_t type)); + +/* Finally, define the extended device structure. */ +#define gx_device_vector_common\ + gx_device_common;\ + gs_memory_t *v_memory;\ + /* Output element writing procedures */\ + const gx_device_vector_procs *vec_procs;\ + /* Output file */\ + char fname[fname_size + 1];\ + FILE *file;\ + stream *strm;\ + byte *strmbuf;\ + uint strmbuf_size;\ + /* Graphics state */\ + gs_imager_state state;\ + float dash_pattern[max_dash];\ + gx_drawing_color fill_color, stroke_color;\ + gs_id no_clip_path_id; /* indicates no clipping */\ + gs_id clip_path_id;\ + /* Other state */\ + gs_point scale; /* device coords / scale => output coords */\ + bool in_page; /* true if any marks on this page */\ + gx_device_bbox *bbox_device; /* for tracking bounding box */\ + /* Cached values */\ + gx_color_index black, white +#define vdev_proc(vdev, p) ((vdev)->vec_procs->p) + +#define vector_initial_values\ + 0, /* v_memory */\ + 0, /* vec_procs */\ + { 0 }, /* fname */\ + 0, /* file */\ + 0, /* strm */\ + 0, /* strmbuf */\ + 0, /* strmbuf_size */\ + { 0 }, /* state */\ + { 0 }, /* dash_pattern */\ + { 0 }, /* fill_color ****** WRONG ****** */\ + { 0 }, /* stroke_color ****** WRONG ****** */\ + gs_no_id, /* clip_path_id */\ + gs_no_id, /* no_clip_path_id */\ + { X_DPI/72.0, Y_DPI/72.0 }, /* scale */\ + 0/*false*/, /* in_page */\ + 0, /* bbox_device */\ + gx_no_color_index, /* black */\ + gx_no_color_index /* white */ + +struct gx_device_vector_s { + gx_device_vector_common; +}; + +/* st_device_vector is never instantiated per se, but we still need to */ +/* extern its descriptor for the sake of subclasses. */ +extern_st(st_device_vector); +#define public_st_device_vector() /* in gdevvec.c */\ + gs_public_st_suffix_add3_final(st_device_vector, gx_device_vector,\ + "gx_device_vector", device_vector_enum_ptrs,\ + device_vector_reloc_ptrs, gx_device_finalize, st_device, strm, strmbuf,\ + bbox_device) +#define st_device_vector_max_ptrs (st_device_max_ptrs + 3) + +/* ================ Utility procedures ================ */ + +/* Initialize the state. */ +void gdev_vector_init(P1(gx_device_vector * vdev)); + +/* Reset the remembered graphics state. */ +void gdev_vector_reset(P1(gx_device_vector * vdev)); + +/* Open the output file and stream, with optional bbox tracking. */ +int gdev_vector_open_file_bbox(P3(gx_device_vector * vdev, uint strmbuf_size, + bool bbox)); + +#define gdev_vector_open_file(vdev, strmbuf_size)\ + gdev_vector_open_file_bbox(vdev, strmbuf_size, false) + +/* Get the current stream, calling beginpage if in_page is false. */ +stream *gdev_vector_stream(P1(gx_device_vector * vdev)); + +/* Bring the logical operation up to date. */ +/* May call setlogop. */ +int gdev_vector_update_log_op(P2(gx_device_vector * vdev, + gs_logical_operation_t lop)); + +/* Bring the fill color up to date. */ +/* May call setfillcolor. */ +int gdev_vector_update_fill_color(P2(gx_device_vector * vdev, + const gx_drawing_color * pdcolor)); + +/* Bring state up to date for filling. */ +/* May call setflat, setfillcolor, setlogop. */ +int gdev_vector_prepare_fill(P4(gx_device_vector * vdev, + const gs_imager_state * pis, + const gx_fill_params * params, + const gx_drawing_color * pdcolor)); + +/* Bring state up to date for stroking. Note that we pass the scale */ +/* for the line width and dash offset explicitly. */ +/* May call setlinewidth, setlinecap, setlinejoin, setmiterlimit, */ +/* setdash, setflat, setstrokecolor, setlogop. */ +int gdev_vector_prepare_stroke(P5(gx_device_vector * vdev, + const gs_imager_state * pis, + const gx_stroke_params * params, + const gx_drawing_color * pdcolor, + floatp scale)); + +/* Write a polygon as part of a path (type = gx_path_type_none) */ +/* or as a path. */ +/* May call moveto, lineto, closepath (if close); */ +/* may call beginpath & endpath if type != none. */ +int gdev_vector_write_polygon(P5(gx_device_vector * vdev, + const gs_fixed_point * points, uint count, + bool close, gx_path_type_t type)); + +/* Write a rectangle. This is just a special case of write_polygon. */ +int gdev_vector_write_rectangle(P7(gx_device_vector * vdev, + fixed x0, fixed y0, fixed x1, fixed y1, + bool close, gx_rect_direction_t dir)); + +/* Write a clipping path by calling the path procedures. */ +/* May call the same procedures as writepath. */ +int gdev_vector_write_clip_path(P2(gx_device_vector * vdev, + const gx_clip_path * pcpath)); + +/* Bring the clipping state up to date. */ +/* May call write_rectangle (q.v.), write_clip_path (q.v.). */ +int gdev_vector_update_clip_path(P2(gx_device_vector * vdev, + const gx_clip_path * pcpath)); + +/* Close the output file and stream. */ +void gdev_vector_close_file(P1(gx_device_vector * vdev)); + +/* ---------------- Image enumeration ---------------- */ + +/* Define a common set of state parameters for enumerating images. */ +#define gdev_vector_image_enum_common\ + gx_image_enum_common;\ + /* Set by begin_image */\ + gs_memory_t *memory; /* from begin_image */\ + gx_image_enum_common_t *default_info; /* non-0 iff using default implementation */\ + gx_image_enum_common_t *bbox_info; /* non-0 iff passing image data to bbox dev */\ + int width, height;\ + int bits_per_pixel; /* (per plane) */\ + uint bits_per_row; /* (per plane) */\ + /* Updated dynamically by image_data */\ + int y /* 0 <= y < height */ +typedef struct gdev_vector_image_enum_s { + gdev_vector_image_enum_common; +} gdev_vector_image_enum_t; + +extern_st(st_vector_image_enum); +#define public_st_vector_image_enum() /* in gdevvec.c */\ + gs_public_st_ptrs2(st_vector_image_enum, gdev_vector_image_enum_t,\ + "gdev_vector_image_enum_t", vector_image_enum_enum_ptrs,\ + vector_image_enum_reloc_ptrs, default_info, bbox_info) + +/* + * Initialize for enumerating an image. Note that the last argument is an + * already-allocated enumerator, not a pointer to the place to store the + * enumerator. + */ +int gdev_vector_begin_image(P10(gx_device_vector * vdev, + const gs_imager_state * pis, const gs_image_t * pim, + gs_image_format_t format, const gs_int_rect * prect, + const gx_drawing_color * pdcolor, const gx_clip_path * pcpath, + gs_memory_t * mem, const gx_image_enum_procs_t * pprocs, + gdev_vector_image_enum_t * pie)); + +/* End an image, optionally supplying any necessary blank padding rows. */ +/* Return 0 if we used the default implementation, 1 if not. */ +int gdev_vector_end_image(P4(gx_device_vector * vdev, + gdev_vector_image_enum_t * pie, bool draw_last, gx_color_index pad)); + +/* ================ Device procedures ================ */ + +/* Redefine get/put_params to handle OutputFile. */ +dev_proc_put_params(gdev_vector_put_params); +dev_proc_get_params(gdev_vector_get_params); + +/* ---------------- Defaults ---------------- */ + +/* fill_rectangle may call setfillcolor, dorect. */ +dev_proc_fill_rectangle(gdev_vector_fill_rectangle); +/* fill_path may call prepare_fill, writepath, write_clip_path. */ +dev_proc_fill_path(gdev_vector_fill_path); +/* stroke_path may call prepare_stroke, write_path, write_clip_path. */ +dev_proc_stroke_path(gdev_vector_stroke_path); +/* fill_trapezoid, fill_parallelogram, and fill_triangle may call */ +/* setfillcolor, setlogop, beginpath, moveto, lineto, endpath. */ +dev_proc_fill_trapezoid(gdev_vector_fill_trapezoid); +dev_proc_fill_parallelogram(gdev_vector_fill_parallelogram); +dev_proc_fill_triangle(gdev_vector_fill_triangle); + +#endif /* gdevvec_INCLUDED */ diff --git a/pstoraster/genarch.c b/pstoraster/genarch.c new file mode 100644 index 0000000000..a8f308bffc --- /dev/null +++ b/pstoraster/genarch.c @@ -0,0 +1,163 @@ +/* Copyright (C) 1989, 1995, 1996, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Generate a header file (arch.h) with parameters */ +/* reflecting the machine architecture and compiler characteristics. */ + +#include "stdpre.h" +#include + +/* We should write the result on stdout, but the original Turbo C 'make' */ +/* can't handle output redirection (sigh). */ + +private void +section(FILE * f, char *str) +{ + fprintf(f, "\n\t /* ---------------- %s ---------------- */\n\n", str); +} + +int +main(int argc, char *argv[]) +{ + char *fname = argv[1]; + long one = 1; + char *ffs = "ffffffffffffffff"; /* 8 bytes */ + int ffs_strlen = strlen(ffs); + 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; + 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"); + + section(f, "Scalar alignments"); + +#define OFFSET_IN(s, e) (int)((char *)&s.e - (char *)&s) + fprintf(f, "#define arch_align_short_mod %d\n", OFFSET_IN(ss, s)); + fprintf(f, "#define arch_align_int_mod %d\n", OFFSET_IN(si, i)); + fprintf(f, "#define arch_align_long_mod %d\n", OFFSET_IN(sl, l)); + fprintf(f, "#define arch_align_ptr_mod %d\n", OFFSET_IN(sp, p)); + fprintf(f, "#define arch_align_float_mod %d\n", OFFSET_IN(sf, f)); + fprintf(f, "#define arch_align_double_mod %d\n", OFFSET_IN(sd, d)); +#undef OFFSET_IN + + section(f, "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_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)); + + section(f, "Unsigned max values"); + +#define PRINT_MAX(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) + PRINT_MAX("uchar", unsigned char, "unsigned char", ""); + PRINT_MAX("ushort", unsigned short, "unsigned short", ""); + PRINT_MAX("uint", unsigned int, "unsigned int", ""); + PRINT_MAX("ulong", unsigned long, "unsigned long", "L"); + +#undef PRINT_MAX + + section(f, "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..5df931e78e --- /dev/null +++ b/pstoraster/ghost.h @@ -0,0 +1,34 @@ +/* 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Common definitions for interpreter */ + +#ifndef ghost_INCLUDED +# define ghost_INCLUDED + +#include "gx.h" +#include "iref.h" + +#endif /* ghost_INCLUDED */ diff --git a/pstoraster/gp.h b/pstoraster/gp.h new file mode 100644 index 0000000000..39aa8c4aa4 --- /dev/null +++ b/pstoraster/gp.h @@ -0,0 +1,233 @@ +/* Copyright (C) 1991, 1995, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Interface to platform-specific routines */ +/* Requires gsmemory.h, gstypes.h */ + +#ifndef gp_INCLUDED +# define gp_INCLUDED + +/* + * This file defines the interface to ***ALL*** platform-specific routines, + * with the exception of the thread/synchronization interface (gpsync.h). + * The routines are implemented in a gp_*.c file specific to each platform. + * We try very hard to keep this list short! + */ +/* + * gp_getenv is declared in a separate file, because a few places need it + * and don't want to include any of the other gs definitions. + */ +#include "gpgetenv.h" + +/* ------ 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()); + +/* ------ File naming and accessing ------ */ + +/* + * Define the maximum size of a file name returned by gp_open_scratch_file + * or gp_open_printer. (This should really be passed as an additional + * parameter, but it would break too many clients to make this change now.) + * Note that this is the size of the buffer, not the maximum number of + * characters: the latter is one less, because of the terminating \0. + */ +#define gp_file_name_sizeof 128 + +/* 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[gp_file_name_sizeof], + 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)); + +/* Force given file into binary mode (no eol translations, etc) */ +/* if 2nd param true, text mode if 2nd param false */ +bool gp_setmode_binary(P2(FILE * pfile, bool 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)); + +/* ------ 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. + * + * Note that if the file name is null (0-length), it may be replaced with + * the name of a scratch file. + */ +FILE *gp_open_printer(P2(char fname[gp_file_name_sizeof], int binary_mode)); + +/* Close the connection to the printer. */ +void gp_close_printer(P2(FILE * pfile, const char *fname)); + +/* ------ 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)); + +#endif /* gp_INCLUDED */ diff --git a/pstoraster/gp_getnv.c b/pstoraster/gp_getnv.c new file mode 100644 index 0000000000..fbf997f32a --- /dev/null +++ b/pstoraster/gp_getnv.c @@ -0,0 +1,60 @@ +/* Copyright (C) 1997 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Standard implementation of gp_getenv */ +#include "stdio_.h" +#include "string_.h" +#include "gsmemory.h" +#include "gstypes.h" +#include "gp.h" + +/* Import the C getenv function. */ +extern char *getenv(P1(const char *)); + +/* Get the value of an environment variable. See gp.h for details. */ +int +gp_getenv(const char *key, char *ptr, int *plen) +{ + const char *str = getenv(key); + + if (str) { + int len = strlen(str); + + if (len < *plen) { + /* string fits */ + strcpy(ptr, str); + *plen = len + 1; + return 0; + } + /* string doesn't fit */ + *plen = len + 1; + return -1; + } + /* missing key */ + if (*plen > 0) + *ptr = 0; + *plen = 1; + return 1; +} diff --git a/pstoraster/gp_nofb.c b/pstoraster/gp_nofb.c new file mode 100644 index 0000000000..49c50ae8a5 --- /dev/null +++ b/pstoraster/gp_nofb.c @@ -0,0 +1,58 @@ +/* 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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_nsync.c b/pstoraster/gp_nsync.c new file mode 100644 index 0000000000..0163cf5a23 --- /dev/null +++ b/pstoraster/gp_nsync.c @@ -0,0 +1,120 @@ +/* Copyright (C) 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Dummy thread / semaphore / monitor implementation */ +#include "std.h" +#include "gserror.h" +#include "gserrors.h" +#include "gpsync.h" + +/* ------- Synchronization primitives -------- */ + +/* Semaphores */ + +uint +gp_semaphore_sizeof(void) +{ + return sizeof(gp_semaphore); +} + +int +gp_semaphore_open(gp_semaphore * sema) +{ + if (sema) + *(int *)sema = 0; + return 0; +} + +int +gp_semaphore_close(gp_semaphore * sema) +{ + return 0; +} + +int +gp_semaphore_wait(gp_semaphore * sema) +{ + if (*(int *)sema == 0) + return_error(gs_error_unknownerror); + --(*(int *)sema); + return 0; +} + +int +gp_semaphore_signal(gp_semaphore * sema) +{ + ++(*(int *)sema); + return 0; +} + +/* Monitors */ + +uint +gp_monitor_sizeof(void) +{ + return sizeof(gp_monitor); +} + +int +gp_monitor_open(gp_monitor * mon) +{ + if (mon) + mon->dummy_ = 0; + return 0; +} + +int +gp_monitor_close(gp_monitor * mon) +{ + return 0; +} + +int +gp_monitor_enter(gp_monitor * mon) +{ + if (mon->dummy_ != 0) + return_error(gs_error_unknownerror); + mon->dummy_ = &mon; + return 0; +} + +int +gp_monitor_leave(gp_monitor * mon) +{ + if (mon->dummy_ != &mon) + return_error(gs_error_unknownerror); + mon->dummy_ = 0; + return 0; +} + +/* Thread creation */ + +int +gp_create_thread(gp_thread_creation_callback_t proc, void *proc_data) +{ + /* Just call the procedure now. */ + (*proc)(proc_data); + return 0; +} diff --git a/pstoraster/gp_unifn.c b/pstoraster/gp_unifn.c new file mode 100644 index 0000000000..aa128faaba --- /dev/null +++ b/pstoraster/gp_unifn.c @@ -0,0 +1,61 @@ +/* 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* 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..7d6bf0ba82 --- /dev/null +++ b/pstoraster/gp_unifs.c @@ -0,0 +1,440 @@ +/*Copyright 1993-2000 by Easy Software Products. + Copyright 1993, 1995, 1996, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* "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 *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[gp_file_name_sizeof], + const char *mode) +{ /* The -8 is for XXXXXX plus a possible final / and -. */ + int len = gp_file_name_sizeof - strlen(prefix) - 8; + + /* + * MRS - Hello? TEMP is a DOS thing, TMPDIR is the UNIX thing. + * Also, we should default to /var/tmp, since the root + * partition is often small. + */ + + if (gp_getenv("TMPDIR", fname, &len) != 0) + strcpy(fname, "/var/tmp/"); + else { + 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); +} + +/* Set a file into binary or text mode. */ +int +gp_setmode_binary(FILE * pfile, bool mode) +{ + return 0; /* Noop under Unix */ +} + +/* ------ 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')) { + dlputs("[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) +{ + const 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..e705af6359 --- /dev/null +++ b/pstoraster/gp_unix.c @@ -0,0 +1,173 @@ +/* Copyright (C) 1989, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Unix-specific routines for Ghostscript */ +#include "pipe_.h" +#include "string_.h" +#include "time_.h" +#include "gx.h" +#include "gsexit.h" +#include "gp.h" + +/* + * 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; + const long 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[gp_file_name_sizeof], 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..aaaf2b7343 --- /dev/null +++ b/pstoraster/gpcheck.h @@ -0,0 +1,65 @@ +/* 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Interrupt check interface */ + +#ifndef gpcheck_INCLUDED +# define gpcheck_INCLUDED + +/* + * 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 + +#endif /* gpcheck_INCLUDED */ diff --git a/pstoraster/gpgetenv.h b/pstoraster/gpgetenv.h new file mode 100644 index 0000000000..61b75c3884 --- /dev/null +++ b/pstoraster/gpgetenv.h @@ -0,0 +1,50 @@ +/* Copyright (C) 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Interface to platform-specific getenv routine */ + +#ifndef gpgetenv_INCLUDED +# define gpgetenv_INCLUDED + +/* + * Get a value from the environment (getenv). + * + * If the key is missing, set *ptr = 0 (if *plen > 0), set *plen = 1, + * and return 1. + * + * If the key is present and the length len of the value (not counting + * the terminating \0) is less than *plen, copy the value to ptr, set + * *plen = len + 1, and return 0. + * + * If the key is present and len >= *plen, set *plen = len + 1, + * don't store anything at ptr, and return -1. + * + * Note that *plen is the size of the buffer, not the length of the string: + * because of the terminating \0, the maximum string length is 1 less than + * the size of the buffer. + */ +int gp_getenv(P3(const char *key, char *ptr, int *plen)); + +#endif /* gpgetenv_INCLUDED */ diff --git a/pstoraster/gpsync.h b/pstoraster/gpsync.h new file mode 100644 index 0000000000..5a16f28d15 --- /dev/null +++ b/pstoraster/gpsync.h @@ -0,0 +1,81 @@ +/* Copyright (C) 1998 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 supports the work of the GNU Project, but is not + affiliated with the Free Software Foundation or the GNU Project. GNU + Ghostscript, as distributed by Aladdin Enterprises, does not require any + GNU software to build or run it. +*/ + +/*$Id$ */ +/* Interface to platform-dependent synchronization primitives */ + +#if !defined(gpsync_INCLUDED) + #define gpsync_INCLUDED + +/* Initial version 4/1/98 by John Desrosiers (soho@crl.com). */ +/* 8/9/98 L. Peter Deutsch (ghost@aladdin.com) Changed ...sizeof to + procedures, added some comments. */ + +/* -------- Synchronization primitives ------- */ + +/* + * Semaphores support wait/signal semantics: a wait operation will allow + * control to proceed iff the number of signals since semaphore creation + * is greater than the number of waits. + */ +typedef struct { + void *dummy_; +} gp_semaphore; + +uint gp_semaphore_sizeof(P0()); +/* + * Hack: gp_semaphore_open(0) succeeds iff it's OK for the memory manager + * to move a gp_semaphore in memory. + */ +int gp_semaphore_open(P1(gp_semaphore * sema)); +int gp_semaphore_close(P1(gp_semaphore * sema)); +int gp_semaphore_wait(P1(gp_semaphore * sema)); +int gp_semaphore_signal(P1(gp_semaphore * sema)); + +/* + * Monitors support enter/leave semantics: at most one thread can have + * entered and not yet left a given monitor. + */ +typedef struct { + void *dummy_; +} gp_monitor; + +uint gp_monitor_sizeof(P0()); +/* + * Hack: gp_monitor_open(0) succeeds iff it's OK for the memory manager + * to move a gp_monitor in memory. + */ +int gp_monitor_open(P1(gp_monitor * mon)); +int gp_monitor_close(P1(gp_monitor * mon)); +int gp_monitor_enter(P1(gp_monitor * mon)); +int gp_monitor_leave(P1(gp_monitor * mon)); + +/* + * A new thread starts by calling a procedure, passing it a void * that + * allows it to gain access to whatever data it needs. + */ +typedef void (*gp_thread_creation_callback_t) (P1(void *)); +int gp_create_thread(P2(gp_thread_creation_callback_t, void *)); + +#endif /* !defined(gpsync_INCLUDED) */ diff --git a/pstoraster/gs_btokn.ps b/pstoraster/gs_btokn.ps new file mode 100644 index 0000000000..7ad61f8a5a --- /dev/null +++ b/pstoraster/gs_btokn.ps @@ -0,0 +1,313 @@ +% Copyright 1993-2000 by Easy Software Products. +% Copyright 1994, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_btokn.ps 956 2000-03-08 23:15:43Z mike $ +% 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 +dup /SystemNames exch def .installsystemnames + +% 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 + +/.bosheader { % .bosheader + % + dup 0 currentobjectformat 127 add put % object format => BOS tag + 2 index 255 le 2 index 65531 le and { + % Use the short header format: tag toplen(1) totlen(2) + exch 4 add exch + 0 4 getinterval + dup 1 5 -1 roll put + } { + % Use the long header format: tag 0(1) toplen(2) totlen(4) + exch 8 add exch + 0 0 4 2 roll .bosobject exch pop exch pop % store with byte swapping + } ifelse % Stack: shortlen str + exch dup -8 bitshift exch 255 and % str hibyte lobyte + currentobjectformat 1 and 0 eq { % lsb first + exch + } if + 2 index 3 3 -1 roll put + 1 index 2 3 -1 roll put +} .bind 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 + +%%%% MRS - stderr instead of stdout, which is used for output... +/printobject { % printobject - + (%stderr) (w) file 2 index 2 index writeobject pop pop +} odef +/writeobject { % writeobject - + 3 copy exch + % We must allocate the array in local VM + % to avoid a possible invalidaccess. + .currentglobal false .setglobal exch 1 array astore exch .setglobal + .writeobjects pop pop pop +} odef + +% Implement binary error message output. + /.printerror + { $error /binary get .languagelevel 2 ge 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..5d4ada0e49 --- /dev/null +++ b/pstoraster/gs_ccfnt.ps @@ -0,0 +1,100 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_ccfnt.ps 956 2000-03-08 23:15:43Z mike $ +% 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_cff.ps b/pstoraster/gs_cff.ps new file mode 100644 index 0000000000..6ac0ea3e8d --- /dev/null +++ b/pstoraster/gs_cff.ps @@ -0,0 +1,614 @@ +% Copyright (C) 1997 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_cff.ps 956 2000-03-08 23:15:43Z mike $ +% Loader for CFF (compressed) fonts. +% The following are not implemented yet: +% Deleted entries in the Name Index +% Embedded PostScript +% Multiple Master fonts +% CIDFonts +% Chameleon fonts +% Synthetic fonts +% Also, Type 2 charstrings are converted into Type 1 fonts with +% CharstringType = 2, which may or may not be supported. + +30 dict begin + +% ---------------- Standard strings (actually names) ---------------- % + +/StandardStrings mark +% 0 + /.notdef /space /exclam /quotedbl /numbersign + /dollar /percent /ampersand /quoteright /parenleft + /parenright /asterisk /plus /comma /hyphen + /period /slash /zero /one /two + /three /four /five /six /seven + /eight /nine /colon /semicolon /less + /equal /greater /question /at /A + /B /C /D /E /F + /G /H /I /J /K + /L /M /N /O /P +% 50 + /Q /R /S /T /U + /V /W /X /Y /Z + /bracketleft /backslash /bracketright /asciicircum /underscore + /quoteleft /a /b /c /d + /e /f /g /h /i + /j /k /l /m /n + /o /p /q /r /s + /t /u /v /w /x + /y /z /braceleft /bar /braceright + /asciitilde /exclamdown /cent /sterling /fraction +% 100 + /yen /florin /section /currency /quotesingle + /quotedblleft /guillemotleft /guilsinglleft /guilsinglright /fi + /fl /endash /dagger /daggerdbl /periodcentered + /paragraph /bullet /quotesinglbase /quotedblbase /quotedblright + /guillemotright /ellipsis /perthousand /questiondown /grave + /acute /circumflex /tilde /macron /breve + /dotaccent /dieresis /ring /cedilla /hungarumlaut + /ogonek /caron /emdash /AE /ordfeminine + /Lslash /Oslash /OE /ordmasculine /ae + /dotlessi /lslash /oslash /oe /germandbls +% 150 + /onesuperior /logicalnot /mu /trademark /Eth + /onehalf /plusminus /Thorn /onequarter /divide + /brokenbar /degree /thorn /threequarters /twosuperior + /registered /minus /eth /multiply /threesuperior + /copyright /Aacute /Acircumflex /Adieresis /Agrave + /Aring /Atilde /Ccedilla /Eacute /Ecircumflex + /Edieresis /Egrave /Iacute /Icircumflex /Idieresis + /Igrave /Ntilde /Oacute /Ocircumflex /Odieresis + /Ograve /Otilde /Scaron /Uacute /Ucircumflex + /Udieresis /Ugrave /Yacute /Ydieresis /Zcaron +% 200 + /aacute /acircumflex /adieresis /agrave /aring + /atilde /ccedilla /eacute /ecircumflex /edieresis + /egrave /iacute /icircumflex /idieresis /igrave + /ntilde /oacute /ocircumflex /odieresis /ograve + /otilde /scaron /uacute /ucircumflex /udieresis + /ugrave /yacute /ydieresis /zcaron /exclamsmall + /Hungarumlautsmall /dollaroldstyle /dollarsuperior /ampersandsmall /Acutesmall + /parenleftsuperior /parenrightsuperior /twodotenleader /onedotenleader /zerooldstyle + /oneoldstyle /twooldstyle /threeoldstyle /fouroldstyle /fiveoldstyle + /sixoldstyle /sevenoldstyle /eightoldstyle /nineoldstyle /commasuperior +% 250 + /threequartersemdash /periodsuperior /questionsmall /asuperior /bsuperior + /centsuperior /dsuperior /esuperior /isuperior /lsuperior + /msuperior /nsuperior /osuperior /rsuperior /ssuperior + /tsuperior /ff /ffi /ffl /parenleftinferior + /parenrightinferior /Circumflexsmall /hyphensuperior /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 +% 300 + /colonmonetary /onefitted /rupiah /Tildesmall /exclamdownsmall + /centoldstyle /Lslashsmall /Scaronsmall /Zcaronsmall /Dieresissmall + /Brevesmall /Caronsmall /Dotaccentsmall /Macronsmall /figuredash + /hypheninferior /Ogoneksmall /Ringsmall /Cedillasmall /questiondownsmall + /oneeighth /threeeighths /fiveeighths /seveneighths /onethird + /twothirds /zerosuperior /foursuperior /fivesuperior /sixsuperior + /sevensuperior /eightsuperior /ninesuperior /zeroinferior /oneinferior + /twoinferior /threeinferior /fourinferior /fiveinferior /sixinferior + /seveninferior /eightinferior /nineinferior /centinferior /dollarinferior + /periodinferior /commainferior /Agravesmall /Aacutesmall /Acircumflexsmall +% 350 + /Atildesmall /Adieresissmall /Aringsmall /AEsmall /Ccedillasmall + /Egravesmall /Eacutesmall /Ecircumflexsmall /Edieresissmall /Igravesmall + /Iacutesmall /Icircumflexsmall /Idieresissmall /Ethsmall /Ntildesmall + /Ogravesmall /Oacutesmall /Ocircumflexsmall /Otildesmall /Odieresissmall + /OEsmall /Oslashsmall /Ugravesmall /Uacutesmall /Ucircumflexsmall + /Udieresissmall /Yacutesmall /Thornsmall /Ydieresissmall (001.000) + (001.001) (001.002) (001.003) /Black /Bold + /Book /Light /Medium /Regular /Roman + /Semibold +.packtomark def + +% ---------------- Standard encodings ---------------- % + +/StandardEncodings [ + +% StandardEncoding +mark + 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 + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 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 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 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 + 0 111 112 113 114 0 115 116 117 118 119 120 121 122 0 123 + 0 124 125 126 127 128 129 130 131 0 132 133 0 134 135 136 + 137 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 138 0 139 0 0 0 0 140 141 142 143 0 0 0 0 + 0 144 0 0 0 145 0 0 146 147 148 149 0 0 0 0 +.packtomark + +% ExpertEncoding +mark + 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 + 1 229 230 0 231 232 233 234 235 236 237 238 13 14 15 99 + 239 240 241 242 243 244 245 246 247 248 27 28 249 250 251 252 + 0 253 254 255 256 257 0 0 0 258 0 0 259 260 261 262 + 0 0 263 264 265 0 266 109 110 267 268 269 0 270 271 272 + 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 + 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 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 304 305 306 0 0 307 308 309 310 311 0 312 0 0 313 + 0 0 314 315 0 0 316 317 318 0 0 0 158 155 163 319 + 320 321 322 323 324 325 0 0 326 150 164 169 327 328 329 330 + 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 + 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 + 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 +.packtomark + +] readonly def + +% ---------------- Standard Charsets ---------------- % + +% We include an explicit 0 at the beginning of each charset. + +/StandardCharsets [ + +% ISOAdobe +mark + 0 + 1 1 228 { } for +.packtomark + +% Expert +mark + 0 + 1 229 230 231 232 233 234 235 236 237 238 13 14 15 99 239 + 240 241 242 243 244 245 246 247 248 27 28 249 250 251 252 253 + 254 255 256 257 258 259 260 261 262 263 264 265 266 109 110 267 + 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 + 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 + 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 + 316 317 318 158 155 163 319 320 321 322 323 324 325 326 150 164 + 169 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 + 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 + 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 + 374 375 376 377 378 +.packtomark + +% ExpertSubset +mark + 0 + 1 231 232 235 236 237 238 13 14 15 99 239 240 241 242 243 + 244 245 246 247 248 27 28 249 250 251 253 254 255 256 257 258 + 259 260 261 262 263 264 265 266 109 110 267 268 269 270 272 300 + 301 302 305 314 315 158 155 163 320 321 322 323 324 325 326 150 + 164 169 327 328 329 330 331 332 333 334 335 336 337 338 339 340 + 341 342 343 344 345 346 +.packtomark + +] readonly def + +% ---------------- Font loading ---------------- % + +% ------ Utilities ------ % + +/advance { % advance - + f cff eq { /pos pos 3 -1 roll add store } { pop } ifelse +} def +/next { % - next + f read { 1 advance } if +} def +/nextstring { % nextstring + dup 0 eq { + pop () + } { + string f exch readstring pop dup length advance + } ifelse +} def +/card8 % - card8 + /next load +def +/card16 { % - card16 + card8 8 bitshift card8 add +} def +/offset { % offset + 0 exch { 8 bitshift next add } repeat +} def +/sid % - sid + /card16 load +def +/Index { % - Index + mark card16 dup 0 ne { + 1 exch next dup offset pop exch { + dup offset dup 4 -1 roll sub 3 1 roll exch + } repeat pop + } if pop .packtomark + [ exch { nextstring } forall ] readonly +} def +/tokens { % - tokens ... (op# = 12 means EOF) + { + f read not { 12 exit } if + 1 advance + dup 12 eq { pop next 32 add exit } if + dup 28 lt { exit } if + dup 32 lt { + 28 sub { + { card16 32768 xor 32768 sub } + { 4 offset dup 16#7fffffff gt { -1 32 bitshift add } if } + { tokenreal } + { 31 exit } + } exch get exec + } { + dup 247 lt { + 139 sub + } { + 247 sub { + { next 108 add } + { next 364 add } + { next 620 add } + { next 876 add } + { next 108 add neg } + { next 364 add neg } + { next 620 add neg } + { next 876 add neg } + % 255 is deliberately omitted and will cause a rangecheck + } exch get exec + } ifelse + } ifelse + } loop +} def +/tokenbuf 100 string def +/tokenput { % tokenput + tokenbuf 2 index 3 -1 roll put 1 add +} def +/tokenrealarray [ + (0123456789.E) { } forall + [(E) 0 get /tokenput cvx (-) 0 get] cvx + null % will give an error + (-) 0 get + { exit } +] readonly def +/tokenreal { % - tokenreal + 0 { + next exch 1 index -4 bitshift tokenrealarray exch get exec tokenput + % We must leave the byte on the stack temporarily so that + % the exit will see a consistent stack state. + 1 index 15 and tokenrealarray exch get exec tokenput exch pop + } loop + tokenbuf 0 3 -1 roll getinterval cvr exch pop +} def +/Dict { % Dict - + /opdict exch store { + mark tokens opdict exch .knownget { exec } if cleartomark + } loop cleartomark +} def +/idstring { % idstring + dup 391 lt { StandardStrings } { 391 sub strings } ifelse exch get +} def +/idname { % idname + idstring dup type /nametype ne { cvn } if +} def + +% ------ Top dictionary ------ % + +/offput { % offput - + currentdict exch aload length 1 add packedarray cvx + offsets 3 1 roll put +} def +/queueput { % queueput - + 16#7fffffff offsets { pop .min } forall + pos sub nextstring + 3 1 roll aload length 2 add packedarray cvx + [ queued aload pop counttomark 2 add -1 roll ] + /queued exch store +} def +/xxput { % xxput - + 3 1 roll exch put +} def +/putfi { % putfi - + FontInfo xxput +} def +/xdef { % xdef - + exch def +} def +/topdictops mark + 12 { exit } + 0 { idstring /version putfi } + 1 { idstring /Notice putfi } + 32 { idstring /Copyright putfi } + 2 { idstring /FullName putfi } + 3 { idstring /FamilyName putfi } + 4 { idstring /Weight putfi } + 33 { 0 ne /isFixedPitch putfi } + 34 { /ItalicAngle putfi } + 35 { /UnderlinePosition putfi } + 36 { /UnderlineThickness putfi } + 37 { /PaintType xdef } + 38 { /CharstringType xdef } + 39 { counttomark array astore /FontMatrix xdef } + 13 { /UniqueID xdef } + 5 { counttomark array astore /FontBBox xdef } + 40 { /StrokeWidth xdef } + 14 { counttomark array astore /XUID xdef } + 15 { + dup StandardCharsets length lt { + StandardCharsets exch get /charset xdef + } { + { queuecharset } offput + } ifelse + } + 16 { + dup StandardEncodings length lt { + /Encoding xdef + } { + { queueEncoding } offput + } ifelse + } + 17 { { readCharStrings } offput } + 18 { exch /readPrivate cvx 2 packedarray offput } +.dicttomark readonly def + +/readCharStrings { % readCharStrings - + /CharStringArray Index put +} def + +% ------ Charsets and encodings ------ % + +% Note: formats 1 and 2 can overflow the operand stack. +% We'll fix this if it ever becomes necessary. +/charsetformats [ +{ [ 0 CharStringArray length 1 sub { sid } repeat ] +} +{ [ 0 CharStringArray length 1 sub { + dup 0 eq { pop exit } if + sid card8 1 add 2 index .min { exch 1 sub 1 index 1 add } repeat pop + } loop ] +} +{ [ 0 CharStringArray length 1 sub { + dup 0 eq { pop exit } if + sid card16 1 add 2 index .min { exch 1 sub 1 index 1 add } repeat pop + } loop ] +} +] readonly def +/queuecharset { % queuecharset - + { readcharset } queueput +} def +/readcharset { % readcharset - + begin 0 () /SubFileDecode filter /f exch store + charsetformats next get exec /charset exch def end +} def + +/encodingformats [ +{ 1 1 next { next exch Encoding 3 1 roll put } for +} +{ 1 next { + next next 1 add { + % Stack: gid code + Encoding 1 index 3 index put + exch 1 add exch 1 add + } repeat pop + } repeat pop +} +] readonly def +/queueEncoding { % queueEncoding - + { readEncoding } queueput +} def +/readEncoding { % readEncoding - + begin 0 () /SubFileDecode filter /f exch store + /Encoding [ 256 { /.notdef } repeat ] def + next encodingformats 1 index 127 and get exec + 128 ge { + % Read supplementary encodings. + next { + Encoding next sid idname put + } repeat + } if end +} def + +% ------ Private dictionary ------ % + +/deltarray { % -mark- ... deltarray ... + 0 counttomark 1 sub { counttomark -1 roll add dup } repeat pop + counttomark array astore +} def + +/privatedictops mark + 12 { exit } + 6 { deltarray /BlueValues xdef } + 7 { deltarray /OtherBlues xdef } + 8 { deltarray /FamilyBlues xdef } + 9 { deltarray /FamilyOtherBlues xdef } + 41 { /BlueScale xdef } + 42 { /BlueShift xdef } + 43 { /BlueFuzz xdef } + 10 { 1 array astore /StdHW xdef } + 11 { 1 array astore /StdVW xdef } + 44 { deltarray /StemSnapH xdef } + 45 { deltarray /StemSnapV xdef } + 46 { 0 ne /ForceBold xdef } + 47 { /ForceBoldThreshold xdef } + 48 { /lenIV xdef } + 49 { /LanguageGroup xdef } + 50 { /ExpansionFactor xdef } + 51 { /initialRandomSeed xdef } + 19 { { readSubrs } offput } + 20 { /defaultWidthX xdef } + 21 { /nominalWidthX xdef } + % Multiple Master fonts only + 59 { /NDV xdef } + 60 { /CDV xdef } + 61 { /lenBuildCharArray xdef } +.dicttomark readonly def + +/readPrivate { % readPrivate - + exch 1 index f exch () /SubFileDecode filter /f exch def + /Private get begin //privatedictops Dict end + /f cff def advance +} def + +% ------ Main program ------ % + +% We need to pass the file as a parameter for the sake of the PDF +% interpreter. +/StartData { % StartData - + currentfile exch () /SubFileDecode filter ReadData +} def +/ReadData { % ReadData - + + % Initialize. + + 30 dict begin + /cff exch def + /pos 0 def + /resname exch cvlit def + + % Read the header. + + /f cff def + /vmajor next def + /vminor next def + /hdrsize next def + /aoffsize next def + + % Read the Indexes. + + /names Index def + /topdicts Index def + /strings Index def + /gsubrs Index def + + % Read the top Dicts. + + /offsets 50 dict def + /queued [] def + /opdict null def % reserve a slot + /fonts [ topdicts { + 0 () /SubFileDecode filter /f exch def + 40 dict begin + % Preload defaults that differ from PostScript defaults, + % or that are required. + /FontType 1 def + /PaintType 0 def + /CharstringType 2 def + /FontMatrix [0.001 0 0 0.001 0 0] def + /charset StandardCharsets 0 get def + /Encoding 0 def + /FontInfo 10 dict + dup /UnderlinePosition -100 put + dup /UnderlineThickness 50 put + def + /Private 20 dict + gsubrs length 0 ne { dup /GlobalSubrs gsubrs put } if + def + //topdictops Dict + currentdict end + } forall ] def + + % Read other tables with queued offsets. + + DEBUG { offsets length =only ( offsets) = flush } if + { /f cff def + offsets pos 2 copy .knownget not { pop pop exit } if + 3 1 roll undef exec + } loop + offsets length 0 ne { + (Error: missing tables at ) print [ offsets { pop } forall ] == + (Current position is ) print pos == + flush stop + } if + + % Process out-of-order tables. + + DEBUG { queued length =only ( queued) = flush } if + queued { exec } forall + + % Update Encoding and CharStrings. + + fonts { + begin + % Construct the real Encoding. + % The value of Encoding is either a number, for predefined + % encodings, or an array of mixed GIDs and names. + /Encoding mark Encoding + DEBUG { (Encoding: ) print dup === flush } if + dup type /integertype eq { + StandardEncodings exch get { idname } forall + } { + { + dup type /integertype eq { charset exch get idname } if + } forall + } ifelse .packtomark def + % Construct the CharStrings. + % Note that they may only correspond to an initial + % subset of the charset. + /CharStrings charset length CharStringArray length .min dict def + DEBUG { + charset length =only ( charset ) print + CharStringArray length =only ( CharStringArray) = + charset == flush + } if + 0 1 CharStrings maxlength 1 sub { + dup CharStringArray exch get + exch charset exch get idstring + CharStrings xxput + } for + % Remove unwanted entries. + currentdict /charset undef + currentdict /CharStringArray undef + end + } forall + + % Wrap up. + + resname mark 0 1 fonts length 1 sub { + DEBUG { dup =only ( ) print flush } if + dup names exch get + DEBUG { dup == flush } if + exch fonts exch get + dup /FontName 3 index put + 1 index exch definefont + } for .dicttomark + end % temporary dict + end % FontSetInit ProcSet + /FontSet defineresource pop + +} bind def + +% ---------------- Resource category definition ---------------- % + +currentdict end readonly + +languagelevel exch 2 .setlanguagelevel + +/FontSet /Generic /Category findresource dup length dict .copydict +/Category defineresource pop + +/FontSetInit exch /ProcSet defineresource pop + +.setlanguagelevel diff --git a/pstoraster/gs_cidfn.ps b/pstoraster/gs_cidfn.ps new file mode 100644 index 0000000000..f7f9265021 --- /dev/null +++ b/pstoraster/gs_cidfn.ps @@ -0,0 +1,466 @@ +% Copyright (C) 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_cidfn.ps 956 2000-03-08 23:15:43Z mike $ +% ProcSet for implementing CIDFont and CIDMap resources. +% When this is run, systemdict is still writable. + +% ---------------- Defining CIDFont resources ---------------- % + +% Define a CIDFont resource. This is the defineresource implementation for +% the CIDFont resource category. + +/.cidfonttypes where { pop } { /.cidfonttypes 6 dict def } ifelse +.cidfonttypes begin + +% The key in .cidfonttypes is the CIDFontType value; +% the value is a procedure that takes a font name and the CIDFont dictionary +% and replaces the latter with a real font. + +0 { % CIDFontType 0 = FontType 9 + currentglobal 3 1 roll dup gcheck setglobal + dup /FontType 9 put + dup /FontMatrix known not { + dup /FontMatrix [0.001 0 0 0.001 0 0] put + dup /FDArray get { + /FontMatrix get [1000 0 0 1000 0 0] 1 index concatmatrix pop + } forall + } if + dup /FDArray get mark exch { + % Add pro forma entries + currentglobal exch dup gcheck setglobal + dup /FontType 1 put + dup /CharStrings mark /.notdef () .dicttomark put + dup /Encoding [] put + % Create a dummy Subrs array now, if there isn't one here + % already (which can only happen if we're giving another + % name to an existing font). + dup /Private get dup /Subrs known not { + dup /SubrCount .knownget { + array 1 index /Subrs 3 -1 roll put + } if readonly + } if pop + exch setglobal + dup /FontName .knownget not { () } if exch .buildfont1 exch pop + } forall ] 1 index /FDepVector 3 -1 roll put + 3 -1 roll setglobal + 1 index exch .buildfont9 exch pop +} bind def + +1 { % CIDFontType 1 = FontType 10 + dup /FontType 10 put + 1 index exch .buildfont10 exch pop +} bind def + +2 { % CIDFontType 2 = FontType 11 + dup /FontType 11 put + 1 index exch .buildfont11 exch pop +} bind def + +end % .cidfonttypes + +% ---------------- Reading CIDFontType 0 files ---------------- % + +30 dict begin + +% We add the following entries to the CIDFont dictionary, in addition to +% the ones documented by Adobe: +% ReadString - procedure for reading a string from the binary data +% SubrCache - dictionary for caching Subr arrays +% For CIDFonts where we read the data from disk incrementally: +% DataOffset - starting position of data in file +% (if data are in hex) OffsetMap - map from logical data positions to +% physical positions in file + +/StartData % <(Binary)|(Hex)> StartData - + % (currentdict is CID font dict) +{ % If we're loading a resource file, we can just save a + % pointer to the binary data and load it incrementally. + % Check for this by opening the resource file, + % positioning it to currentfile's position plus the + % data length, and checking for %%EndData. + mark + { currentfile fileposition + CIDFontName 100 string ResourceFileName (r) file + mark + { % Stack: (Binary)|(Hex) length -mark- pos resfile + % -mark- + 5 index (Hex) eq + { 1 index 3 index setfileposition + 1 index 5 index .skiphex + %**************** SKIP > AND WHITESPACE SOMEHOW + } + { 1 index 3 index 6 index add setfileposition + } + ifelse + 1 index 9 string readstring pop (%%EndData) ne { stop } if + } + .internalstopped { cleartomark closefile stop } if + pop % pop the mark + } + .internalstopped + { % File is not positionable, load the data now. + cleartomark exch (Hex) eq + { { currentfile exch readhexstring pop } } + { { currentfile exch readstring pop } } + ifelse /ReadString exch def + dup 65535 le + { string ReadString + } + { mark exch + { dup 0 eq { pop exit } if + dup 65535 min dup string ReadString + 3 1 roll sub + } + loop ] + } + ifelse + /GlyphData exch def + % If we were reading hex data, skip past the >. + /ReadString load 2 get { readhexstring } 0 get eq { + currentfile 0 (>) /SubFileDecode filter dup flushfile closefile + } if + /.vmreadstring cvx + } + { % File is positionable, just save a pointer. + % Stack: (Binary)|(Hex) length -mark- pos file + 4 1 roll + /DataOffset exch def + pop /GlyphData exch def + exch (Hex) eq + { % Hex data, build the offset map. + .buildoffsetmap + /.hexreadstring + } + { % Binary data, just skip over it. + currentfile DataOffset GlyphData add setfileposition + /.binaryreadstring + } + ifelse cvx + 2 packedarray cvx + } + ifelse /ReadString exch def + /SubrCache 10 dict def + CIDFontName currentdict /CIDFont defineresource pop + end % CID font dict + end % resource category dict +} bind def + +% Skip a given distance in an ASCIIHex encoded file. We use this at +% rendering time as well. +/.skiphex % .skiphex - +{ exch /ASCIIHexDecode filter dup 3 -1 roll () /SubFileDecode filter + dup flushfile closefile closefile +} bind def + +% Build the map from logical offsets to physical offsets in ASCIIHex +% encoded data. +/.buildoffsetmap +{ /OffsetMap GlyphData 256 idiv 8000 min array def + 2 dict begin + /block GlyphData OffsetMap length idiv def + 0 1 OffsetMap length 1 sub + { OffsetMap exch currentfile fileposition put + currentfile block .skiphex + } + for + GlyphData block mod dup 0 eq + { pop } + { currentfile exch .skiphex } + ifelse + end % scratch dict +} bind def + +currentdict end + +% ---------------- Rendering ---------------- % + +% ------ Generic ------ % + +% Read a string at a given offset in a "file" (binary file, ASCII hex file, +% or GlyphData in RAM). +/.binaryreadstring % .binaryreadstring + { dup 4 -1 roll DataOffset add setfileposition exch readstring pop + } bind def +/.hexreadstring % .hexreadstring +{ % Use the OffsetMap to get to the block of hex data, + % then skip to the correct position by reading. + GlyphData OffsetMap length idiv + % Stack: pos string file blocklen + 3 index 1 index idiv OffsetMap exch get + 2 index exch setfileposition + % Skip the next (pos % blocklen) hex bytes. + 4 -1 roll exch mod 1 index exch .skiphex + % Stack: string file + exch readhexstring pop +} bind def +/.vmreadstring % .vmreadstring +{ GlyphData .stringsreadstring +} bind def +/.stringsreadstring % .stringsreadstring + % +{ dup type /stringtype eq + { 3 1 roll length getinterval + } + { { % Stack: pos string glyphdata + dup 0 get length dup 4 index gt { exit } if + 4 -1 roll exch sub 3 1 roll + dup length 1 sub 1 exch getinterval + } + loop + % Stack: pos string glyphdata glyphdata[0]length + % We know no request can span more than 2 strings. + 3 index 3 index length add 1 index le + { % Request fits in a single string: just return a substring. + pop 0 get 3 1 roll length getinterval + } + { % Request spans 2 strings. Copy the first part. + 1 index 0 get 4 index 3 -1 roll 1 index sub getinterval + 2 index copy + % Copy the second part. + % Stack: pos str glyphdata str1 + length exch 1 get 0 3 index length + 3 index sub getinterval 2 index 3 1 roll putinterval + exch pop + } + ifelse + } + ifelse +} bind def + +% Interpret a byte string as a (big-endian) integer. +/.cvbsi % .cvbsi +{ 0 exch { exch 8 bitshift add } forall +} bind def + +% Read an integer from binary data. +/.readint % .readint +{ string ReadString .cvbsi +} bind def + +% Read the glyph data for a given CID. The CIDFont is currentdict. +% Note that the data must be read into the same VM as the CharStrings +% dictionary of the selected subfont. +/.readglyphdata { % .readglyphdata + currentdict /GlyphDirectory .knownget { + dup type /arraytype eq { + 1 index exch get + } { + 1 index exch .knownget not { null } if + } ifelse + dup null eq { + FDepVector 0 get exch + } { + FDBytes 0 eq { + FDepVector 0 get exch + } { + % Note: FDBytes > 1 is not supported. + dup 0 get FDepVector exch get + exch dup length 1 sub 1 exch getinterval + } ifelse + } ifelse + } { + FDBytes GDBytes add mul CIDMapOffset add + dup FDBytes .readint exch + FDBytes add dup GDBytes .readint + exch GDBytes add FDBytes add GDBytes .readint + % Stack: fd pos nextpos + 1 index sub dup 0 eq { + pop pop pop FDepVector 0 get null + } { + % Stack: fd pos len + FDepVector 4 -1 roll get + dup /CharStrings get gcheck .currentglobal exch .setglobal + % Stack: pos len subfont global + 4 2 roll string ReadString exch .setglobal + } ifelse + } ifelse +} bind def + +% ------ CIDFontType 0 ------ % + +% Read some Subrs for the current Type 1 subfont. +% The subfont's Private dict is currentdict; the CIDFont itself is the +% next dictionary on the stack. +/.readsubrs { % .readsubrs + 1 SubrCount 1 sub { + dup SDBytes mul SubrMapOffset add + dup SDBytes .readint exch SDBytes add SDBytes .readint + 1 index sub string ReadString 2 index 3 1 roll put + } for +} bind def + +% Ensure that all the Subrs for the current Type 1 subfont are loaded. +% The subfont's Private dict is currentdict; the CIDFont itself is the +% next dictionary on the stack. +/.loadsubrs { + currentdict /SubrMapOffset .knownget { + Subrs 0 get null ne { + pop % We've already loaded the Subrs. + } { + currentglobal exch currentdict gcheck setglobal + SubrCache 1 index .knownget { + % We've already loaded some Subrs at this offset. + % Make sure we've got as many as we need. + dup length SubrCount lt { + % We need to load more. + SubrCount array exch 1 index copy length .readsubrs + SubrCache 3 -1 roll 2 index put + } if + } { + % We haven't loaded any Subrs at this offset yet. + SubrCount array 0 .readsubrs + SubrCache 3 -1 roll 2 index put + } ifelse + Subrs copy pop setglobal + } ifelse + } if +} bind def + +% BuildGlyph procedure for CIDFontType 0. +% ****** WHY NOT USE .type1execchar FOR THIS? ****** +% The name %Type9BuildGlyph is known to the interpreter. +/.cid0buildstring 10 string def +(%Type9BuildGlyph) cvn { % %Type9BuildGlyph - + .currentglobal 3 1 roll 1 index gcheck .setglobal + 1 index begin + dup .readglyphdata dup null eq + { %**** HANDLE NOTDEF **** + } + if + % Stack: cidfont cid subfont charstring +dup null eq { pop pop pop pop } { %**** WRONG **** + 4 -1 roll pop + exch dup /Private get begin .loadsubrs end + 3 -1 roll //.cid0buildstring cvs cvn 3 1 roll + dup /CharStrings get 3 index 4 -1 roll put + setfont + 1000 0 setcharwidth %**** WRONG **** + 0 0 moveto glyphshow +} ifelse %**** WRONG **** + end + .setglobal +} bind def + +% ------ CIDFontType 2 ------ % + +% BuildGlyph procedure for CIDFontType 2. +% ****** ADD THE OUTLINE STRING AS AN ARGUMENT TO .type42execchar. ****** +% The name %Type11BuildGlyph is known to the interpreter. +(%Type11BuildGlyph) cvn { % %Type11BuildGlyph - + .currentglobal 3 1 roll 1 index gcheck .setglobal + 1 index begin + % We must be prepared for out-of-range CIDs. + dup GDBytes mul GDBytes string CIDMap + mark 4 1 roll { .stringsreadstring } .internalstopped { + %**** 0 IS WRONG + cleartomark 0 GDBytes string CIDMap .stringsreadstring + } { + exch pop + } ifelse .cvbsi + % Stack: cidfont cid glyphindex +%**************** GlyphDirectory is not supported yet. +( + currentdict /GlyphDirectory .knownget +) pop false + { dup type /arraytype eq + { 1 index exch get } + { 1 index exch .knownget not { null } if } + ifelse + dup null eq + { %**** HANDLE NOTDEF + } + if + 1 index exch .type42execchar + } + { 1 index exch .type42execchar + } + ifelse + end + .setglobal +} bind def + +% ---------------- Define resources ---------------- % + +languagelevel exch 2 .setlanguagelevel + +% Define the CIDInit ProcSet resource. +% The ProcSet dictionary is still on the stack. + +/CMap /Generic /Category findresource dup length dict .copydict +/Category defineresource pop + % We might have loaded CMap support already. +/CIDInit /ProcSet 2 copy resourcestatus { + pop pop findresource dup length 4 index length add dict .copydict + 4 -1 roll exch .copydict +} { + 3 -1 roll +} ifelse exch defineresource pop + +% Define the CIDFont resource category. +% We break out .buildcidfont because it appears that at least for +% Type 32 (CIDFontType 4) fonts, the font can be registered in the Font +% category with only a CIDFontType and no FontType. +/.buildcidfont { % .buildcidfont + % + dup /CIDFontType get //.cidfonttypes exch get exec +} odef + +/CIDFont /Generic /Category findresource dup length dict .copydict +dup /InstanceType /dicttype put +dup /DefineResource { + .buildcidfont + /Generic /Category findresource /DefineResource get exec +} put +/Category defineresource pop + +% Add the new FontType resources. + +9 1 11 { dup /FontType defineresource pop } for + +% Add the new FMapType resource. + +9 dup /FMapType defineresource pop + +% Define the CIDMap resource category. +% These aren't documented, but it's clear what they are for: +% to give names to CIDMaps for CIDFontType 2 fonts. + +/CIDMap /Generic /Category findresource dup length dict .copydict +dup /.CheckResource { + % Allow either a string or an array of strings. + dup type dup /stringtype eq + { pop true + } + { dup /arraytype eq exch /packedarraytype eq or + { true exch { type /stringtype ne { pop false exit } if } forall + } + { false + } + ifelse + } + ifelse +} bind put +/Category defineresource pop + +.setlanguagelevel diff --git a/pstoraster/gs_cmap.ps b/pstoraster/gs_cmap.ps new file mode 100644 index 0000000000..e2ce96d65f --- /dev/null +++ b/pstoraster/gs_cmap.ps @@ -0,0 +1,256 @@ +% Copyright (C) 1995, 1996, 1997 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_cmap.ps 956 2000-03-08 23:15:43Z mike $ +% ProcSet for implementing CMap resources. +% When this is run, systemdict is still writable. + +% NOTE: Rearranged fonts are not implemented yet. + +% ---------------- Public operators ---------------- % + +% composefont doesn't appear in CMap files -- it's documented in +% the "PostScript Language Reference Manual Supplement". +/composefont { % composefont + 10 dict begin + /CMap 2 index dup type /dicttype ne { /CMap findresource } if def + /Encoding [ 0 1 4 index length 1 sub { } for ] def + /FDepVector [ 2 index { + dup type /dicttype ne { + dup /CIDFont resourcestatus { + pop pop /CIDFont findresource + } { + /Font findresource + } ifelse + } if + } forall ] readonly def + /FMapType 9 def + /FontMatrix matrix def + /FontName 3 index def + /CMap load /WMode .knownget { /WMode exch def } if + /FontType 0 def + pop pop currentdict end /Font defineresource +} bind odef + +% ---------------- CMap operators ---------------- % + +30 dict begin + +% Our internal .CodeMaps structure is an array of two arrays: array 0 +% is the map for defined characters, array 1 is the map for notdefs. +% Both are multi-level arrays indexed by the successive bytes of the +% character code. Each value is either a sub-array, null, a character name, +% a CID (an integer), or a character code (expressed as a byte string). +% All of the arrays are read-only after they have been built. +% +% Note that the code in zfcmap.c that constructs the C structures from +% the PostScript structures has intimate knowledge of the above format. + +/.getmap { .CodeMaps exch get } bind def +/.putmap { .CodeMaps exch 3 -1 roll put } bind def + +% ------ Font-level operators ------ % + +/begincmap % - begincmap - + { /.CodeMaps [256 array 256 array] def + } bind def +/endcmap % - endcmap - + { /.CodeMaps .CodeMaps .endmap def + /CodeMap null def % for .buildcmap + currentdict end .buildcmap begin + } bind def + +/begincodespacerange % begincodespacerange - + { pop mark + } bind def +/endcodespacerange % ... endcodespacerange - + { counttomark 2 idiv + { .CodeMaps { 3 copy .addcodespacerange pop } forall pop pop + } 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 + { 0 .getmap .endmapchar 0 .putmap + } bind def + +/beginbfrange % beginbfrange - + { pop mark + } bind def +/endbfrange % ... + % endbfrange - + { 0 .getmap counttomark 3 idiv { .addbfrange } repeat 0 .putmap 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 - + { 0 .getmap .endmapchar 0 .putmap + } bind def + +/begincidrange % begincidrange - + { pop mark + } bind def +/endcidrange % ... endcidrange - + { 0 .getmap counttomark 3 idiv { { 1 add } exch .addmaprange exch pop } repeat + 0 .putmap pop + } bind def + +/.endmapchar % -mark- ... .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 - + { { } 1 .getmap .addmaprange 1 .putmap pop + } bind def + +% ---------------- Resource category definition ---------------- % + +currentdict end + +languagelevel exch 2 .setlanguagelevel + +/CMap /Generic /Category findresource dup length dict .copydict +/Category defineresource pop + % We might have loaded CID font support already. +/CIDInit /ProcSet 2 copy { findresource } .internalstopped + % An interior `stopped' might have reset VM allocation to local. +true .setglobal + { pop pop 3 -1 roll } + { dup length 4 index length add dict .copydict 4 -1 roll exch .copydict } +ifelse exch defineresource pop + +.setlanguagelevel diff --git a/pstoraster/gs_cmdl.ps b/pstoraster/gs_cmdl.ps new file mode 100644 index 0000000000..7293e09232 --- /dev/null +++ b/pstoraster/gs_cmdl.ps @@ -0,0 +1,188 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_cmdl.ps 956 2000-03-08 23:15:43Z mike $ +% 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..b31a392281 --- /dev/null +++ b/pstoraster/gs_dbt_e.ps @@ -0,0 +1,67 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_dbt_e.ps 956 2000-03-08 23:15:43Z mike $ +% 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..eedd980826 --- /dev/null +++ b/pstoraster/gs_diskf.ps @@ -0,0 +1,232 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_diskf.ps 956 2000-03-08 23:15:43Z mike $ +% 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_dpnxt.ps b/pstoraster/gs_dpnxt.ps new file mode 100644 index 0000000000..2d2573ff7d --- /dev/null +++ b/pstoraster/gs_dpnxt.ps @@ -0,0 +1,120 @@ +% Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_dpnxt.ps 956 2000-03-08 23:15:43Z mike $ +% gs_dpnxt.ps +% NeXT Display PostScript extensions + +% Define the operation values for compositing. These must match the values +% in gsdpnext.h, which also are the ones from the NeXT documentation. +% We put them in systemdict, which seems like as good a place as any. +mark + /Clear /Copy /Sover /Sin /Sout /Satop /Dover /Din /Dout /Datop /Xor + /PlusD /PlusL /Highlight % not sure about Highlight +counttomark { counttomark 1 sub def } repeat pop + +% We implement readimage and sizeimage using the following 3 otherwise +% undocumented lower-level operators: +% +% .sizeimagebox +% +% +% - .sizeimageparams +% +% +% .getbitsrect +% +% NOTE: These operators are subject to change without notice! + +% Implement readimage using .getbitsrect. Experimentation on a NeXT system +% shows that the data is always returned in order of increasing device Y, +% regardless of the CTM. +% +% Note that we can't make stack protection work for this operator, +% because it must remove its operands from the stack before calling +% the supplied procedure(s). + +/readimage { % [... ] + % readimage - + .sizeimageparams exch { + % multiproc = true. If N > 1, store the procedures in an array. + exch pop 1 index { 1 add } if + % Stack: ... string alpha? nprocs + dup 1 eq { + pop false % only 1 procedure, multiproc is irrelevant + } { + dup array 4 1 roll 3 add 2 roll astore 3 1 roll true + } ifelse + } { + % multiproc = false. + pop pop false + } ifelse + % Map the rectangle to device coordinates. + % Stack: x y w h proc(s) str alpha? multi? + 8 -4 roll matrix .sizeimagebox pop 8 4 roll + % Make sure we allocate the operand array in local VM + % to avoid a possible invalidaccess. + .currentglobal false .setglobal 9 1 roll + exch { 1 } { 0 } ifelse exch % alpha is last, if present + exch 4 1 roll 8 array astore exch .setglobal + { % Read out a block of scan lines and pass them to the procedure. + % Stack: [x y w h alpha? proc(s) str multi?] -- we must consume this. + dup 3 get 0 eq { pop exit } if + aload 9 1 roll pop exch pop currentdevice 7 1 roll + % Always read out the data as standard (not native) pixels. + .sizeimageparams pop pop exch .getbitsrect + % Stack: [x y w h alpha? proc(s) str multi?] hread substr + 3 -1 roll + % Stack: hread substr [x y w h alpha? proc(s) str multi?] + dup 1 2 copy get 5 index add put + % Stack: hread substr [x y' w h alpha? proc(s) str multi?] + dup 3 2 copy get 6 -1 roll sub put + % Stack: substr [x y' w h' alpha? proc(s) str multi?] + dup 5 get exch 7 get { + % multiproc = true, pass each plane to a different procedure. + % Stack: substr procs + 0 1 2 index length 1 sub { + % Push 1 plane and its procedure under the top 2 elements. + % Stack: ... substr procs plane# + 2 index length 2 index length idiv % bytes per plane + dup 2 index mul exch + % Stack: ... substr procs plane# start length + 4 index 3 1 roll getinterval 4 1 roll + 2 copy get 4 1 roll pop + } for + exch pop length 2 mul .execn + } { + % multiproc = false, just call the procedure. + exec + } ifelse + } //systemdict /exec get 3 packedarray cvx loop +} bind odef + +% Implement sizeimage using lower-level operators. + +/sizeimage { % sizeimage + % + % + .sizeimagebox 5 -2 roll pop pop + .sizeimageparams 3 -1 roll 4 1 roll +} bind odef diff --git a/pstoraster/gs_dps.ps b/pstoraster/gs_dps.ps new file mode 100644 index 0000000000..354d8155b5 --- /dev/null +++ b/pstoraster/gs_dps.ps @@ -0,0 +1,205 @@ +% Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_dps.ps 956 2000-03-08 23:15:43Z mike $ +% Initialization file for Display PostScript functions. + +% ------ Contexts ------ % + +% To create a context with private local VM, we use the .localfork +% operator to actually create the context, the new VM, and an empty +% userdict, and then we call the .initlocaldicts procedure to make +% local copies of the initial contents of the dictionaries in local VM. +% savedlocaldicts in systemdict is a global read-only dictionary whose +% elements are global read-only copies of these initial contents; +% we just copy its elements into local VM and install them in systemdict. +% userdict and internaldict require special handling. + +% Switching between contexts with different local VMs requires +% changing the bindings in systemdict that reference local objects. +% For this purpose, each userdict has an entry called localdicts +% which holds the local copies of the elements of savedlocaldicts, +% plus internaldict. The context switching code in the interpreter +% effectively copies this dictionary into systemdict. +% NOTE: the name localdicts is known to the interpreter. + +% Switching between contexts also requires resetting the user parameters. +% The interpreter records the value of userparams (a local dictionary +% referenced from systemdict) for each context, and uses it for this. +% See gs_lev2.ps for more details. +% NOTE: the name userparams is known to the interpreter. + +% Save copies of local dictionaries at the end of system initialization. +% Also save the initial gstate. +/.savelocalstate { + .currentglobal true .setglobal + //systemdict /savedlocaldicts mark //systemdict { + dup gcheck { + pop pop + } { + dup type /dicttype eq { + % Save a copy of this dictionary in global VM. + dup maxlength dict .copydict readonly + } { + pop pop + } ifelse + } ifelse + } forall .dicttomark readonly .forceput % systemdict is read-only + % Create localdicts for the current context. + false .setglobal + userdict /localdicts mark savedlocaldicts { + pop dup load + } forall /internaldict dup load + .dicttomark readonly put + % Save a copy of the initial gstate. + true .setglobal + //systemdict /savedinitialgstate gstate readonly put + .setglobal +} .bind def + +% Initialize local dictionaries and gstate when creating a new context. +% Note that until this completes, we are in the anomalous situation of +% having systemdict point to dictionaries that are in a non-current +% local VM. Because of this, we turn off garbage collection temporarily. +/.copylocal { % .copylocal + % Copy a dictionary to the current (local) VM, + % and make it read-only if its current definition is. + dup maxlength dict .copydict + 1 index load wcheck not { readonly } if +} .bind def +% When this is called, the dictionary stack is in its initial state, +% and there is (anomalously) only one gstate on the gstate stack. +/.initlocaldicts { % - .initlocaldicts - + -2 vmreclaim + .currentglobal //systemdict begin + false .setglobal + % Since localdicts doesn't exist yet, references from + % systemdict to local objects won't get restored if + % a context switch happens in this code. Therefore, + % until localdicts is defined, we have to keep all our + % state on the operand stack. + + % Acquire userdict. + %****** WRONG IF NON-STANDARD INITIAL DSTACK ****** + countdictstack array dictstack + { dup gcheck not { exit } if pop } forall + % Create localdicts with a local copy of each dictionary, + % except for userdict and userparams, which just need + % to be filled in. + mark savedlocaldicts { + 1 index /userdict eq { + % Stack: userdict mark ... /userdict inituserdict + counttomark 1 add index exch .copydict + } { + 1 index /userparams eq { + % Stack: userparams mark ... /userparams inituserparams + userparams .copydict + } { + .copylocal + } ifelse + } ifelse + } forall /internaldict dup .makeinternaldict .makeoperator + .dicttomark readonly /localdicts exch put + % localdicts is now defined in userdict. + % Copy the definitions into systemdict. + localdicts { .forcedef } forall + % Set the user parameters. + userparams readonly .setuserparams + % Establish the initial gstate(s). + /savedinitialgstate .systemvar setgstate gsave + % Wrap up. + end .setglobal +} odef + +% Create a context with private local VM. +% The .localfork operator does all the work, but we must ensure that +% .initlocaldicts gets called when the new context starts up. +/localfork { % ... + % + % localfork + .currentglobal true .setglobal 3 index + dup dup xcheck + exch type dup /arraytype eq exch /packedarraytype eq or and not { + pop .setglobal /localfork cvx /typecheck signalerror + } if + {exec .initlocaldicts} aload pop + 3 1 roll 3 packedarray cvx + 4 1 roll 5 -1 roll pop .setglobal .localfork +} odef + +% Fork a context that shares VM. We still need to fill in userparams +% when the new context starts up. +/.postfork { % - .postfork - + % Initialize the user parameters. + savedlocaldicts /userparams get userparams .copydict readonly pop +} odef +/fork { % ... fork + .currentglobal false .setglobal 1 index + dup dup xcheck + exch type dup /arraytype eq exch /packedarraytype eq or and not { + pop .setglobal /fork cvx /typecheck signalerror + } if + {exec .postfork} aload pop + 3 1 roll 3 packedarray cvx + 3 1 roll exch pop .setglobal .fork +} odef + +% ------ Halftone phase ------ % + +/sethalftonephase { % sethalftonephase - + -1 2 index 2 index .setscreenphase pop pop +} odef +/currenthalftonephase { % - currenthalftonephase + 0 .currentscreenphase +} odef + +% ------ Device-source images ------ */ + +.imagetypes 2 /.image2 load put + +% ------ Device information ------ % + +/.deviceinfodict mark + /Colors null /GrayValues null /RedValues null /GreenValues null + /BlueValues null /ColorValues null +.dicttomark readonly def +/deviceinfo { % - deviceinfo + currentdevice //.deviceinfodict .getdeviceparams .dicttomark readonly +} odef + +% The current implementation allocates a 2-element array each time. +% Perhaps we should change this to 2 separate parameters for X and Y? +/.wtdict mark + /wtranslation null +.dicttomark readonly def +/wtranslation { % - wtranslation + currentdevice //.wtdict .getdeviceparams exch pop exch pop aload pop +} odef +currentdict /.wtdict .undef + +% ------ View clipping ------ % + +/rectviewclip { % rectviewclip - + % rectviewclip - + newpath .rectappend viewclip +} odef diff --git a/pstoraster/gs_dps1.ps b/pstoraster/gs_dps1.ps new file mode 100644 index 0000000000..f343b571a2 --- /dev/null +++ b/pstoraster/gs_dps1.ps @@ -0,0 +1,147 @@ +% Copyright (C) 1997 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_dps1.ps 956 2000-03-08 23:15:43Z mike $ +% Initialization file for most of the Display PostScript functions +% that are also included in Level 2. + +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 + .forcedef % LocalFontDirectory is local, systemdict is global + .setglobal .FontDirectory + } + { /LocalFontDirectory .FontDirectory + .forcedef % LocalFontDirectory is local, systemdict is global + 50 dict + } +ifelse def + +end % systemdict +level2dict begin + +% setshared must rebind FontDirectory to the appropriate one of +% Local or SharedFontDirectory. + +/.setglobal % .setglobal - + { dup .setglobal + //systemdict /FontDirectory .currentglobal + { //SharedFontDirectory } + { /LocalFontDirectory .systemvar } % can't embed ref to local VM + ifelse .forceput pop % LocalFontDirectory is local, systemdict is global + } .bind odef % must bind .forceput and .setglobal + % even if NOBIND in effect +/setshared /.setglobal load def +.currentglobal setshared + +% See below for changes in save and restore. + +% ------ Fonts ------ % + +/selectfont % selectfont - + { 1 index findfont + 1 index dup type /arraytype eq { makefont } { scalefont } ifelse + setfont pop pop + } odef +% undefinefont has to take local/global VM into account. +/undefinefont % undefinefont - + { .FontDirectory 1 index .undef + .currentglobal + { % Current mode is global; delete from local directory too. + //systemdict /LocalFontDirectory .knownget + { 1 index .undef } + if + } + { % Current mode is local; if there was a shadowed global + % definition, copy it into the local directory. + //systemdict /SharedFontDirectory .knownget + { 1 index .knownget + { .FontDirectory 2 index 3 -1 roll put } + if + } + if + } + ifelse pop + } 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 - + { dup //restore % bind even if NOBIND + /LocalFontDirectory .systemvar + 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 + .currentglobal .setglobal % Rebind FontDirectory according to current VM. + pop + } bind odef + +% ------ Miscellaneous ------ % + +/undef /.undef load def + +end % level2dict diff --git a/pstoraster/gs_dps2.ps b/pstoraster/gs_dps2.ps new file mode 100644 index 0000000000..e375505ab4 --- /dev/null +++ b/pstoraster/gs_dps2.ps @@ -0,0 +1,200 @@ +% Copyright (C) 1990, 1996, 1997 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_dps2.ps 956 2000-03-08 23:15:43Z mike $ +% Initialization file for basic Display PostScript functions +% that are also included in Level 2. + +level2dict begin + +% ------ Halftones ------ % + +/.makestackdict + { { counttomark -1 roll } forall .dicttomark + } bind def +/currenthalftone % - 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 { % sethalftone - + % We must create the new dictionary in the same VM as the + % operand; otherwise, invalidaccess errors may occur. + .currentglobal 1 index dup gcheck .setglobal + 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 .setglobal pop +} 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 % .fix...screen + % + { dup dup /HalftoneType get 1 eq + { dup wcheck not { dup length .copydict } if + dup /Frequency 5 index put + dup /Angle 4 index put + } + if + } bind def +/setscreen % setscreen - + { dup type /dicttype eq + { .fixsethalftonescreen sethalftone pop pop pop } + { //setscreen } + ifelse + } odef +/setcolorscreen % setcolorscreen - + { dup type /dicttype eq + { .fixsethalftonescreen sethalftone 12 { 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 % - currentscreen 60 0 + { .currenthalftone + { { .fixcurrenthalftonescreen } % halftone + { } % screen + { 12 3 roll 9 { pop } repeat % colorscreen + dup type /dicttype eq { .fixcurrenthalftonescreen } if + } + } + exch get exec + } odef +/currentcolorscreen % - currentcolorscreen (60 0 )*4 + { .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 +/.UserObjects { + .userdict /UserObjects +} odef +% In order to get proper error recovery behavior, we need to be careful +% not to pop any operands from the stack until we're done. +% The code below faithfully duplicates the apparent array-growing +% behavior of Adobe interpreters. +/defineuserobject { % defineuserobject - + .UserObjects .knownget { + length dup 3 index le { + % Stack: index value len + 2 index eq { 1 index 2 mul } { 1 index 1 add } ifelse + .localarray .UserObjects get + 1 index copy pop + .UserObjects 3 -1 roll put + } { + pop + } ifelse + } { + .UserObjects 3 index 1 add 10 .max .localarray put + } ifelse + .UserObjects get 2 index 2 index put pop pop +} odef +/execuserobject { % execuserobject - + .UserObjects get 1 index get exch pop exec +} odef +/undefineuserobject { % undefineuserobject - + .UserObjects get 1 index null put pop +} odef + +% ------ Cache control ------ % + +% Dummy definitions for cache control operators + +/ucachestatus { % - ucachestatus -mark- ? ? ? ? + mark 0 0 0 0 .userdict /.ucachesize .knownget not { 0 } if +} odef +/setucacheparams { % -mark- ... setucacheparams - + % Provoke an appropriate error if needed. + counttomark 1 lt { () 0 get } if + 0 or .userdict /.ucachesize 2 index 0 .max put cleartomark +} odef + +end % level2dict diff --git a/pstoraster/gs_epsf.ps b/pstoraster/gs_epsf.ps new file mode 100644 index 0000000000..fcccb3e330 --- /dev/null +++ b/pstoraster/gs_epsf.ps @@ -0,0 +1,67 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_epsf.ps 956 2000-03-08 23:15:43Z mike $ +% Allow the interpreter to recognize MS-DOS EPSF file headers, and skip to +% the PostScript section of the file. + +/.runnoepsf /run load def +/.epsfheader def +/run + { dup type /filetype ne { (r) file } if + % Check for MS-DOS EPSF file (see Red Book p. 729). + true exch 0 1 3 + { % Stack: true file index + 1 index read dup { pop dup .epsfheader 3 index get eq } if + { pop pop } % if matched, don't need the character + { % unread characters (wasn't EPSF) + 2 index exch unread % unread mismatch character + dup { % loop unreading backwards in .epsfheader + 1 sub dup .epsfheader exch get 2 index exch unread + } repeat pop + exch not exch exit % change true to false + } + ifelse + } + for exch % Stack: file true/false + { % This block is executed if the file is MS-DOS EPSF. + % Build up the little-endian byte offset and length. + 2 + { 1 0 4 + { 2 index read not { pop exit } if % if EOF, let error happen + 2 index mul add exch 256 mul exch + } + repeat exch pop exch + } + repeat + % Stack: offset length file + % Use flushfile to skip quickly to the start of the + % PostScript section. + dup 4 -1 roll 12 sub () /SubFileDecode filter flushfile + % Now interpret the PostScript. + exch () /SubFileDecode filter cvx .runexec + } + { .runnoepsf + } + ifelse + } odef diff --git a/pstoraster/gs_fform.ps b/pstoraster/gs_fform.ps new file mode 100644 index 0000000000..17dfbef74f --- /dev/null +++ b/pstoraster/gs_fform.ps @@ -0,0 +1,100 @@ +% Copyright (C) 1995, 1996, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_fform.ps 956 2000-03-08 23:15:43Z mike $ +% Form caching implemented in PostScript. + +% This implementation doesn't do the right thing about halftone or +% Pattern phase, but the Pattern cache doesn't either.... + +% The Form cache key is the Form dictionary; the value is an array +% of 2 elements [CTM pattern_instance]. +% +% In order to prevent restore from clearing the cache, we explicitly +% push the cache entries on the stack before a restore and reinstall them. +currentglobal false setglobal +/.formcachedict 20 dict def % must be local +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 + +/.execform1 { + dup /Implementation known not { + dup /FormType get 1 ne { /rangecheck signalerror } if + % The Implementation is a Pattern that will draw the form. + currentglobal 1 index gcheck setglobal + % Stack: form global + 10 dict begin + /PatternType 1 def + /PaintType 1 def % colored + /TilingType 1 def % irrelevant + % Copy the BBox to the correct VM. + /BBox 2 index /BBox get 4 array copy exch 1 index def + % Set XStep and YStep to very large numbers, + % so we won't get multiple copies of the form. + /XStep 1 index dup 2 get exch 0 get sub 100 mul def + /YStep exch dup 3 get exch 1 get sub 100 mul def + /PaintProc 2 index /PaintProc get def + currentdict end readonly + % Stack: form global impl + exch setglobal + 1 index /Implementation 3 -1 roll .forceput + } if + .formcachedict 1 index .knownget { + % Check whether we can use the cached value. + % Stack: form cachevalue + matrix currentmatrix true 0 1 3 { + % Stack: form cachevalue curmat true index + 3 index 0 get 1 index get exch 3 index exch get ne { + pop pop false exit + } if + } for exch pop + } { + false + } ifelse not + { % Make a new cache entry. + gsave + matrix currentmatrix dup 4 0 put dup 5 0 put dup setmatrix + % Stack: form mat + 1 index /Implementation get + 2 index /Matrix get + makepattern 2 array astore + .formcachedict 2 index 2 index put + grestore + } if + % Stack: form cachevalue + -1 0 0 transform + 2 { exch round cvi } repeat .setscreenphase + 1 get setpattern + /BBox get aload pop + exch 3 index sub exch 2 index sub rectfill +} .bind odef % must bind .forceput + +.formtypes 1 /.execform1 load put + +setglobal diff --git a/pstoraster/gs_fonts.ps b/pstoraster/gs_fonts.ps new file mode 100644 index 0000000000..c413882ace --- /dev/null +++ b/pstoraster/gs_fonts.ps @@ -0,0 +1,934 @@ +% Copyright (C) 1990, 1995, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_fonts.ps 956 2000-03-08 23:15:43Z mike $ +% 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 SUBSTFONT is defined, make it the default font. +/SUBSTFONT where { pop /defaultfontname /SUBSTFONT load def } if + +% Define a reliable way of accessing FontDirectory in systemdict. +/.FontDirectory +{ /FontDirectory .systemvar +} .bind odef + +% 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 + +% Define a temporary string for local use, since using =string +% interferes with some PostScript programs. +/.fonttempstring 128 string 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 .fonttempstring 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 + /dir true + /dll true + /doc true + /drv true + /exe true + /fon true + /fot true + /h true + /o true + /obj true + /pfm true + /pss true % Adobe Multiple Master font instances + /txt true +.dicttomark def +/.scan1fontstring 128 string def +/.scanfontheaders [(%!PS-Adobe*) (%!FontType*)] 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 flush } 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 + +% Create the dictionary that registers the .buildfont procedure (called by +% definefont) for each FontType. +/buildfontdict 20 dict def + +% Register Type 3 fonts, which are always supported, for definefont. +buildfontdict 3 /.buildfont3 cvx put + +% Register Type 0 fonts if they are supported. Strictly speaking, +% we should do this in its own file (gs_type0.ps), but since this is +% the only thing that would be in that file, it's simpler to put it here. +/.buildfont0 where { pop buildfontdict 0 /.buildfont0 cvx put } if + +% Define definefont. This is a procedure built on a set of operators +% that do all the error checking and key insertion. +/.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 +/.completefont { + { % 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. + % Note that some types of font don't have an Encoding. + dup /Encoding .knownget { + dup length 65 ge { + 64 get + dup /congruent eq { SymbolEncoding pop } if + /a9 eq { DingbatsEncoding pop } if + } { + pop + } ifelse + } if + } + ifelse + true exch + dup /FontType known not { + % This might be a CIDFont. + dup /CIDFontType known { + /.buildcidfont where { + pop exch pop false exch + } if + } if + } if + exch { + dup /FontType get //buildfontdict exch get exec + } { + .buildcidfont + } ifelse + + DISKFONTS + { FontFileDirectory 2 index known + { dup /FontFile FontFileDirectory 4 index get .growput + } + if + } + if + readonly % stack: name fontdict + } stopped { /invalidfont signalerror } if +} bind odef +/definefont + { .completefont + % 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 + } odef + +% Define a procedure for defining aliased fonts. +% We use this only for explicitly aliased fonts, not substituted fonts: +% we think this matches the observed behavior of Adobe interpreters. +/.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 in this case, do a cvn. + % We might also be defining (as an alias) a global font + % whose FontName is a local non-string, if someone passed a + % garbage value to findfont. In this case, just don't + % call definefont at all. + 2 index dup type /stringtype eq exch .gcheck or 1 index .gcheck not or + { /FontName 3 index dup type /stringtype eq { cvn } if put + % Don't bind in definefont, since Level 2 redefines it. + /definefont .systemvar exec + } + { .completefont pop exch pop + } + ifelse 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 { + % According to Ed Taft, Adobe interpreters push userdict + % before loading a font, and pop it afterwards. + userdict begin + cvx exec + end +} 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] + [(Frut) /Helvetica] + [(Geneva) /Helvetica] + [(Helv) /Helvetica] + [(NewYork) /Times] + [(Pala) /Palatino] + [(Sans) /Helvetica] + [(Schlbk) /NewCenturySchlbk] + [(Serif) /Times] + [(Swiss) /Helvetica] + [(Times) /Times] + [(Univers) /Helvetica] + % Substitute for Adobe Multiple Master fonts. + [(Minion) /Times] + [(Myriad) /Helvetica] + [(MyriadPkg) /Helvetica-Narrow] + % 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 type dup /stringtype eq exch /nametype eq or + { dup length string cvs } { () } ifelse + {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 exec + % 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. We must pop the arguments at the very end, +% so that stack protection will be effective. + +/definefont { % definefont + dup /FontMatrix known { + //definefont + } { + 2 copy /FontName get findfont //definefont exch pop exch pop + } ifelse +} bind odef + +/scalefont { % scalefont + 1 index /FontMatrix known { + //scalefont + } { + 1 index /FontName get findfont 1 index //scalefont + exch pop exch pop + } ifelse +} bind odef + +/makefont { % makefont + 1 index /FontMatrix known { + //makefont + } { + 1 index /FontName get findfont 1 index //makefont + exch pop exch pop + } ifelse +} bind odef + +/setfont { % setfont - + dup /FontMatrix known { + //setfont + } { + dup /FontName get findfont //setfont pop + } ifelse +} 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, +% but it still needs to restore the stacks reliably if it fails, +% so we do all the work in an operator. +/.findfont { + mark 1 index + //systemdict begin .dofindfont + % Define any needed aliases. + counttomark 1 sub { .aliasfont } repeat end + exch pop exch pop +} odef +/findfont { + .findfont +} 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. Make sure we're not already + % looking for the default 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 + % Substitute for the font. Don't alias. + /SUBSTFONT where { + pop QUIET not { + (Substituting for font ) print dup =only + (.\n) print flush + } if + cleartomark mark defaultfontname + } { + 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 + % Remove all the accumulated aliases. + counttomark 1 add 1 roll cleartomark mark exch + } ifelse + } + 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. Look for a file with the + % same name as the requested font. + dup dup type /nametype eq { .namestring } if .loadfontloop + } + { % Try each element of the Fontmap in turn. + false exch % (in case we exhaust the list) + % Stack: fontname false fontmaplist + { 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 + % Stack: font true -or- fontname false + { true + } + { % None of the Fontmap entries worked. + % Try loading a file with the same name + % as the requested font. + dup dup type /nametype eq { .namestring } if .loadfontloop + } + ifelse + } + ifelse + } + ifelse + } bind def +% Attempt to load a font from a file. +/.loadfontloop % .loadfontloop true + % .loadfontloop false + { % See above regarding the use of 'loop'. + + { + % Is the font name a string? + dup type /stringtype ne + { QUIET not + { (Can't find font with non-string name: ) print dup =only (.\n) print flush + } + if pop false exit + } + if + % 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 .systemvar exec + % Remove the fake definition, if any. + .FontDirectory 3 index .undef + 1 index (r) file .loadfont .FontDirectory exch + /.setglobal .systemvar 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 and FontType defined. +% (We define FontType only for the sake of some questionable code in the +% Apple Printer Utility 2.0 font inquiry code.) +% +% Note that this procedure only creates fake fonts in the FontDirectory +% associated with the current VM. This is because in multi-context systems, +% creating the fake fonts in local VM leads to undesirable complications. +/.definefakefonts + { + } + { + (gs_fonts FAKEFONTS) VMDEBUG + Fontmap { + pop dup type /stringtype eq { cvn } if + .FontDirectory 1 index known not { + 2 dict dup /FontName 3 index put + dup /FontType 1 put + .FontDirectory 3 1 roll put + } { + pop + } ifelse + } forall + } +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 % current VM is global + } def % don't bind, .current/setglobal get redefined + +% ---------------- 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_init.ps b/pstoraster/gs_init.ps new file mode 100644 index 0000000000..6a670b6382 --- /dev/null +++ b/pstoraster/gs_init.ps @@ -0,0 +1,1521 @@ +% Copyright 1993-2000 by Easy Software Products. +% Copyright 1989, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_init.ps 956 2000-03-08 23:15:43Z mike $ +% 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. +550 +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 +systemdict exch + { % userdict wasn't already set up by iinit.c. + dup /userdict + currentdict dup 200 .setmaxlength % userdict + .forceput % userdict is local, systemdict is global + } +if begin + +% 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 /BATCH known /BATCH exch 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 /NOINTERPOLATE known /NOINTERPOLATE exch def +currentdict /NOPAGEPROMPT known /NOPAGEPROMPT 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 /STRICT known /STRICT 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 + +/.currentuserparams where { + pop mark + % The Adobe implementations appear to have very large maximum + % stack sizes. This turns out to actually make a difference, + % since some badly-behaved files include extremely long procedures, + % or construct huge arrays on the operand stack. + % We reset the stack sizes now so that we don't have to worry + % about overflowing the (rather small) built-in stack sizes + % during initialization. + /MaxDictStack 500 + /MaxExecStack 5000 + /MaxOpStack 50000 + .dicttomark .setuserparams +} if + +% 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 + +% 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 100 mod dup 0 ne { 10 idiv } { pop } ifelse (.) + 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. +/obind { % obind + 1 index exch .makeoperator +} .bind def +/odef { % odef - + 1 index exch .makeoperator def +} .bind def + +% Define a special version of def for storing local objects into global +% dictionaries. Like .forceput, this exists only during initialization. +/.forcedef { % .forcedef - + currentdict 3 1 roll .forceput +} .bind odef + +% Define procedures for accessing variables in systemdict and userdict +% regardless of the contents of the dictionary stack. +/.systemvar { % .systemvar + //systemdict exch get +} .bind odef +/.userdict { % - .userdict + /userdict .systemvar +} .bind odef +/.uservar { % .uservar + .userdict exch get +} .bind odef + +% If we're delaying binding, remember everything that needs to be bound later. +DELAYBIND NOBIND not and + { .currentglobal false .setglobal + systemdict /.delaybind 1500 array .forceput + .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 + { /.delaybind .systemvar dup length 0 ne + { .delaycount 2 index put + .userdict /.delaycount .delaycount 1 add put + } + { pop .bind + } + ifelse + } .bind def + } if + +%**************** BACKWARD COMPATIBILITY +/hwsizedict mark /HWSize null .dicttomark readonly def +/copyscanlines { % copyscanlines + 0 3 1 roll 3 index //hwsizedict .getdeviceparams + exch pop exch pop aload pop 3 2 roll + 0 exch null exch .getbitsrect exch pop +} bind odef +currentdict /hwsizedict .undef +/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 +/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 redefined if setpagedevice is present. +/.beginpage { } odef +% In LanguageLevel 3, copypage erases the page. +/copypage { + .languagelevel 3 ge + 1 .endpage { + .currentnumcopies 1 index .outputpage + (>>copypage, press to continue<<\n) .confirm + dup { erasepage } if + } if pop .beginpage +} odef +/currentmatrix { + .currentmatrix 6 index astore pop +} 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 exec + % Only pop systemdict if it is still the top element, + % because this is apparently what Adobe interpreters do. + currentdict //systemdict eq { end } if + } odef +% .endpage is redefined if setpagedevice is present. +/.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 +% To satisfy the Genoa FTS, executive must be a procedure, not an operator. +/executive + { { NOPROMPT not { prompt } if + { (%statementedit) (r) file } stopped + { pop pop $error /errorname get /undefinedfilename eq + { .clearerror exit } if % EOF + handleerror null % ioerror?? + } + if + cvx { .runexec } execute + } loop + } bind def +/filter + { //filterdict 1 index .knownget + { exch pop exec } + { /filter load /undefined signalerror } + ifelse + } odef +/handleerror + { /errordict .systemvar /handleerror get exec } bind def +/identmatrix [1.0 0.0 0.0 1.0 0.0 0.0] readonly def +/identmatrix + { dup 0 //identmatrix putinterval } 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 +% Execute a file. +% Level 2 uses 2 .stop to clear the e-stack for a successful startjob: +% we detect that here, since we need to handle this even if we start out +% without job control in effect. +% +% What we push on the e-stack is the following to be executed in this order: +% .runexec1 .runexec2 +/.runexec1 { % .runexec1 - + dup type /filetype ne { cvx exec } if + cvx null 2 .stopped + % If we got back here from a startjob, just keep going. + % startjob replaces the null on the o-stack with a procedure + % to be executed when we get back here. + dup null ne { exec true } { pop false } ifelse +} bind def +/.runexec2 { % .runexec2 - + exch { + .runexec + } { + dup type /filetype ne { cvx exec } if + closefile + } ifelse +} bind def +/.runexec { % .runexec - + cvlit /.runexec1 cvx 1 index /.runexec2 cvx 4 .execn +} bind def +% The following is only for compatibility with Adobe interpreters. +/setdash { + 1 index length 11 gt { /setdash load /limitcheck signalerror } if + //setdash +} odef +/setdevice + { .setdevice { erasepage } if } odef +/setlinecap { + dup 2 gt { /setlinecap load /rangecheck signalerror } if + .setlinecap +} odef +/setlinejoin { + dup 2 gt { /setlinejoin load /rangecheck signalerror } if + .setlinejoin +} odef +/setmatrix { + dup aload pop .setmatrix pop +} odef +/showpage { + 0 .endpage .doneshowpage { + .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 { BATCH { null 0 .quit } { executive } ifelse } def +% 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. +/.internalstopped { null 1 .stopped null ne } bind def +/store { % Don't alter operands before completing. + 1 index where { 2 index 2 index put pop pop } { def } ifelse +} odef +% NOTE: the name typenames is known to (initialized by) the interpreter. +/type { + //typenames .type +} odef +% When running in Level 1 mode, this interpreter is supposed to be +% compatible with PostScript "version" 54.0 (I think). +/version (54.0) readonly def + +% internaldict is defined in systemdict, but is allocated in local VM. +% We make a procedure for creating it, since we must create a new one +% for each context with private local VM. +/.makeinternaldict { + .currentglobal false .setglobal + [ /dup .systemvar 1183615869 /eq .systemvar + [ /pop .systemvar 10 dict ] cvx + [ /internaldict /cvx .systemvar /invalidaccess /signalerror cvx ] cvx + /ifelse .systemvar + ] cvx executeonly + exch .setglobal +} odef +systemdict /internaldict dup .makeinternaldict .makeoperator +.forceput % proc is local, systemdict is global +% Move superexec to internaldict if superexec is defined. +currentdict /superexec .knownget { + 1183615869 internaldict /superexec 3 -1 roll put + currentdict /superexec .undef +} 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 + { /devicedict .systemvar 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 + { % We don't want to bind 'run' into this procedure, + % since run may get redefined. + findlibfile + { exch pop /run .systemvar exec } + { /undefinedfilename signalerror } + ifelse + } bind def +/selectdevice + { finddevice setdevice .setdefaultscreen } bind def +/signalerror % signalerror - + { /errordict .systemvar 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 +} bind def +/write= { + 1 index exch write=only (\n) writestring +} bind def +%%%% MRS - Send = output to stderr, since stdout is for output. +/=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 NOPAGEPROMPT or NOPROMPT is true) + % and wait for the user to type something. + % If the user just types a newline, flush it. + NOPAGEPROMPT NOPROMPT or { 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 { % .execute + stopped $error /newerror get and + { handleerror flush true } { false } ifelse +} bind def +/execute { % execute - + .execute pop +} odef +% Define an execute analogue of runlibfile0. +/execute0 { % execute0 - + .execute { /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. +% We don't use the obvious { (%stdin) run }, because we want the file to be +% reopened if a startjob does a restore. +/.runstdin { + { { (%stdin) (r) file cvx } .runexec } execute0 +} bind def +% Define the procedure that the C code uses for running commands +% given on the command line with -c. We turn the string into a file so that +% .runexec can do the right thing with a startjob. +/.runstring { + .currentglobal exch true .setglobal + 0 () .subfiledecode + exch .setglobal cvx { .runexec } execute +} bind def +% Define the procedure that the C code uses to set up for executing +% a string that may be received in pieces. +/.runstringbegin { + .currentglobal true .setglobal + { .needinput } bind 0 () .subfiledecode + exch .setglobal cvx .runexec +} bind 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'. + 1 .instopped { null eq { pop pop stop } if } if + $error /.inerror get 1 .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 dup maxlength =only + } if + /gcheck where { + pop gcheck { ((G)) } { ((L)) } ifelse print + } { + 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 /errorname null put + $error /errorinfo .undef + 0 .setoserrno + } bind def + +% Define $error. This must be in local VM. +.currentglobal false .setglobal +/$error 40 dict .forcedef % $error is local, systemdict is global + % 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 +.forcedef % errordict is local, systemdict is global +.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 + { /.printerror .systemvar 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 +.forcedef % FontDirectory is local, systemdict is global + +% 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. +% To satisfy the Genoa FTS, findencoding must be a procedure, not an operator. +/rootfont where { pop /findencoding { .findencoding } def } if + +% Define .registerencoding. +% NOTE: the name registeredencodings is known to (initialized by and shared +% with) the interpreter. +/.registerencoding { % .registerencoding - + % Check that the array is indexable. + % (It might still be a string, but then the .namestring will fail.) + dup 0 0 getinterval pop + % Check that all the elements of the array are names. + dup { .namestring pop } forall + % Do the store. + //registeredencodings 2 index 2 index readonly put pop pop +} bind odef +systemdict /registeredencodings .undef + +% 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} .internalstopped 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 (or higher) functionality is implemented, enable it now. +/.setlanguagelevel where { + pop 2 .setlanguagelevel + % If the resource machinery is loaded, fix up some things now. + /.fixresources where { pop .fixresources } if +} if +/ll3dict where { + pop 3 .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. +/undefinefont where { + pop /NullFont undefinefont +} { + FontDirectory /NullFont .undef +} ifelse + +(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 +% The following line used to skip setting of page size and resolution if +% NODISPLAY was selected. We think this was only to save time and memory, +% and it is a bad idea because it prevents setting the resolution in this +% situation, which pstoedit (among other programs) relies on. +%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 /Policies + % Stack: /Policies +1 index /InputAttributes +2 copy get dup length dict .copydict + % Stack: /Policies + % /InputAttributes +dup 0 2 copy get dup length dict .copydict + % Stack: /Policies + % /InputAttributes 0 +dup /PageSize 7 index /PageSize get +put % PageSize in 0 +put % 0 in InputAttributes +put % InputAttributes in pagedevice +% Also change the page size policy so we don't get an error. + % Stack: /Policies +2 copy get dup length dict .copydict + % Stack: /Policies +dup /PageSize 7 put % PageSize in Policies +put % Policies 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 + +% Establish an appropriate halftone screen and BG/UCR functions. +% We make this a procedure so we can call it again when switching devices. + +%%%% MRS - Changed default to 16x16 Floyd dither, matching the CUPS +%%%% image RIP. Also, added missing standard transfer function, +%%%% which is needed by output from many apps... + +% Set the default screen and BG/UCR based on the device resolution and +% process color capability. +/.setdefaultbgucr systemdict /setblackgeneration known { { + processcolors 1 eq { { } } { { pop 0.0 } } ifelse + dup setblackgeneration setundercolorremoval +} } { { +} } ifelse bind def +% 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. +<04> cvn { } def % Apple job separator +<0404> cvn { } def % two of the same +<1b> cvn { } def % MS Windows LaserJet 4 prologue + % (UEL = ESC %-12345X) +<1b45> cvn { } def % PJL reset prologue (ESC E) +<1b451b> cvn { } def % PJL reset epilogue (ESC E + UEL) +<041b> cvn { } def % MS Windows LaserJet 4 epilogue (^D + UEL) +(\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 + 2 index (%std*) .stringmatch or + { 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 + //systemdict /.delaybind {} .forceput % reclaim the space + //systemdict /.bindnow .forceundef % ditto + put + //systemdict /.forcedef .forceundef % remove temptation + //systemdict /.forceput .forceundef % ditto + //systemdict /.forceundef .forceundef % ditto +} .bind odef + +% Turn off array packing, since some PostScript code assumes that +% procedures are writable. +false setpacking + +(END INIT) VMDEBUG + +/.currentuserparams where { + pop + % Remove real user params from psuserparams. + mark .currentuserparams counttomark 2 idiv { + pop psuserparams exch undef + } repeat pop + % Update the copy of the user parameters. + mark .currentuserparams counttomark 2 idiv { + userparams 3 1 roll .forceput % userparams is read-only + } repeat pop + % Turn on idiom recognition, if available. + currentuserparams /IdiomRecognition known { + /IdiomRecognition true .definepsuserparam + } if + psuserparams readonly pop + systemdict /.definepsuserparam undef + % Save a copy of userparams for use with save/restore + % (and, if implemented, context switching). + .currentglobal false .setglobal + mark .currentuserparams psuserparams { } forall .dicttomark readonly + /userparams exch .forcedef % systemdict is read-only + .setglobal +} if +/.currentsystemparams where { + pop + % Remove real system params from pssystemparams. + mark .currentsystemparams counttomark 2 idiv { + pop pssystemparams exch .forceundef + } repeat pop +} if + +% Conditionally turn off image interpolation. +NOINTERPOLATE not { (%END NOINTERPOLATE) .skipeof } if +/.nointerpolate { + dup type /dicttype eq { + dup /Interpolate .knownget not { false } if { + dup gcheck .currentglobal exch .setglobal + exch dup length dict copy + dup /Interpolate .undef + exch .setglobal + } if + } if +} bind odef +/image { .nointerpolate image } bind odef +/imagemask { .nointerpolate imagemask } bind odef +%END NOINTERPOLATE + +% Establish local VM as the default. +false /setglobal where { pop setglobal } { .setglobal } ifelse +$error /.nosetlocal false put + +(END GLOBAL) VMDEBUG + +/.savelocalstate where { + % If we might create new contexts, save away copies of all dictionaries + % referenced from systemdict that are stored in local VM, + % and also save a copy of the initial gstate. + pop .savelocalstate +} { + % If we're *not* running in a multi-context system and FAKEFONTS is + % defined, add the fake fonts to LocalFontDirectory. + .definefakefonts % current VM is local +} ifelse + +% Close up systemdict. +currentdict /filterdict .undef % bound in where needed +currentdict /.cidfonttypes .undef % ditto +currentdict /.colorrenderingtypes .undef % ditto +currentdict /.formtypes .undef % ditto +currentdict /.imagetypes .undef % ditto +currentdict /.imagemasktypes .undef % ditto +currentdict /.patterntypes .undef % ditto +currentdict /.shadingtypes .undef % ditto +end + +% Clean up VM, and enable GC. +/vmreclaim where + { pop NOGC not { 2 vmreclaim 0 vmreclaim } if + } if +DELAYBIND not { + systemdict /.forcedef .undef % remove temptation + systemdict /.forceput .undef % ditto + systemdict /.forceundef .undef % ditto +} if +WRITESYSTEMDICT not { systemdict readonly pop } 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..607d9714f1 --- /dev/null +++ b/pstoraster/gs_iso_e.ps @@ -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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_iso_e.ps 956 2000-03-08 23:15:43Z mike $ +% 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..ee4272dd47 --- /dev/null +++ b/pstoraster/gs_kanji.ps @@ -0,0 +1,166 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_kanji.ps 956 2000-03-08 23:15:43Z mike $ +% 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..e418ea3aa8 --- /dev/null +++ b/pstoraster/gs_ksb_e.ps @@ -0,0 +1,72 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_ksb_e.ps 956 2000-03-08 23:15:43Z mike $ +% 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..fc1294fd30 --- /dev/null +++ b/pstoraster/gs_l2img.ps @@ -0,0 +1,192 @@ +% 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_l2img.ps 956 2000-03-08 23:15:43Z mike $ +% 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 + 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..94c490f8db --- /dev/null +++ b/pstoraster/gs_lev2.ps @@ -0,0 +1,717 @@ +% Copyright (C) 1990, 1996, 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_lev2.ps 956 2000-03-08 23:15:43Z mike $ +% Initialization file for Level 2 functions. +% When this is run, systemdict is still writable, +% but (almost) everything defined here goes into level2dict. + +level2dict begin + +% ------ System and user parameters ------ % + +% User parameters must obey save/restore, and must also be maintained +% per-context. We implement the former, and some of the latter, here +% with PostScript code. NOTE: our implementation assumes that user +% parameters change only as a result of setuserparams -- that there are +% no user parameters that are ever changed dynamically by the interpreter +% (although the interpreter may adjust the value presented to setuserparams) +% +% There are two types of user parameters: those which are actually +% maintained in the interpreter, and those which exist only at the +% PostScript level. We maintain the current state of both types in +% a read-only local dictionary named userparams, defined in systemdict. +% In a multi-context system, each context has its own copy of this +% dictionary. In addition, there is a constant dictionary named +% psuserparams whose keys are the names of user parameters that exist +% only in PostScript and whose values are (currently) arbitrary values +% of the correct datatype: setuserparams uses this for type checking. +% setuserparams updates userparams explicitly, in addition to setting +% any user parameters in the interpreter; thus we can use userparams +% to reset those parameters after a restore or a context switch. +% NOTE: the name userparams is known to the interpreter, and in fact +% the interpreter creates the userparams dictionary. + +% Check parameters that are managed at the PostScript level. +% Currently we allow resetting them iff the new value is of the same type. +/.checksetparams { % + % .checksetparams + 2 index { + % Stack: newdict opname checkdict key newvalue + 3 copy pop .knownget + { type 1 index type ne + { pop pop pop load /typecheck signalerror } + if + dup type /stringtype eq + { dup rcheck not + { pop pop pop load /invalidaccess signalerror } + if + } + if + } + if pop pop + } forall pop pop +} .bind def % not odef, shouldn't reset stacks + +% currentuser/systemparams creates and returns a dictionary in the +% current VM. The easiest way to make this work is to copy any composite +% PostScript-level parameters to global VM. Currently, the only such +% parameters are strings. In fact, we always copy string parameters, +% so that we can be sure the contents won't be changed. +/.copyparam { % .copyparam + dup type /stringtype eq { + .currentglobal true .setglobal + 1 index length string exch .setglobal + copy readonly + } if +} .bind def + +% Some user parameters are managed entirely at the PostScript level. +% We take care of that here. +systemdict begin +/psuserparams 40 dict def +/getuserparam { % getuserparam + /userparams .systemvar 1 index get exch pop +} odef +% Fill in userparams (created by the interpreter) with current values. +mark .currentuserparams +counttomark 2 idiv { + userparams 3 1 roll put +} repeat pop +/.definepsuserparam { % .definepsuserparam - + psuserparams 3 copy pop put + userparams 3 1 roll put +} .bind def +end +/currentuserparams { % - currentuserparams + /userparams .systemvar dup length dict .copydict +} odef +/setuserparams { % setuserparams - + % Check that we will be able to set the PostScript-level + % user parameters. + /setuserparams /psuserparams .systemvar .checksetparams + % Set the C-level user params. If this succeeds, we know that + % the password check succeeded. + dup .setuserparams + % Now set the PostScript-level params. + % The interpreter may have adjusted the values of some of the + % parameters, so we have to read them back. + dup { + /userparams .systemvar 2 index known { + psuserparams 2 index known not { + pop dup .getuserparam + } if + .copyparam + /userparams .systemvar 3 1 roll .forceput % userparams is read-only + } { + pop pop + } ifelse + } forall + % A context switch might have occurred during the above loop, + % causing the interpreter-level parameters to be reset. + % Set them again to the new values. From here on, we are safe, + % since a context switch will consult userparams. + .setuserparams +} .bind odef +% Initialize user parameters managed here. +/JobName () .definepsuserparam + +% Restore must restore the user parameters. +% (Since userparams is in local VM, save takes care of saving them.) +/restore { % restore - + restore /userparams .systemvar .setuserparams +} .bind odef + +% The pssystemparams dictionary holds some system parameters that +% are managed entirely at the PostScript level. +systemdict begin +currentdict /pssystemparams known not { + /pssystemparams 40 dict readonly def +} if +/getsystemparam { % getsystemparam + //pssystemparams 1 index .knownget { exch pop } { .getsystemparam } ifelse +} odef +end +/currentsystemparams { % - currentsystemparams + mark .currentsystemparams //pssystemparams { } forall .dicttomark +} odef +/setsystemparams { % setsystemparams - + % Check that we will be able to set the PostScript-level + % system parameters. + /setsystemparams //pssystemparams .checksetparams + % Set the C-level system params. If this succeeds, we know that + % the password check succeeded. + dup .setsystemparams + % Now set the PostScript-level params. We must copy local strings + % into global VM. + dup + { //pssystemparams 2 index known + { % Stack: key newvalue + .copyparam + //pssystemparams 3 1 roll .forceput % pssystemparams is read-only + } + { pop pop + } + ifelse + } + forall pop +} .bind odef + +% Initialize the passwords. +% NOTE: the names StartJobPassword and SystemParamsPassword are known to +% the interpreter, and must be bound to noaccess strings. +% The length of these strings must be max_password (iutil2.h) + 1. +/StartJobPassword 65 string noaccess def +/SystemParamsPassword 65 string noaccess def + +% Redefine cache parameter setting to interact properly with userparams. +/setcachelimit { + mark /MaxFontItem 2 index .dicttomark setuserparams pop +} .bind odef +/setcacheparams { + % The MaxFontCache parameter is a system parameter, which we might + % not be able to set. Fortunately, this doesn't matter, because + % system parameters don't have to be synchronized between this code + % and the VM. + counttomark 1 add copy setcacheparams + currentcacheparams % mark size lower upper + 3 -1 roll pop + /MinFontCompress 3 1 roll + /MaxFontItem exch + .dicttomark setuserparams + cleartomark +} .bind odef + +% Add bogus user and system parameters to satisfy badly written PostScript +% programs that incorrectly assume the existence of all the parameters +% listed in Appendix C of the Red Book. Note that some of these may become +% real parameters later: code near the end of gs_init.ps takes care of +% removing any such parameters from ps{user,system}params. + +psuserparams begin + /MaxFormItem 100000 def + /MaxPatternItem 20000 def + /MaxScreenItem 48000 def + /MaxUPathItem 5000 def +end + +pssystemparams begin + /CurDisplayList 0 .forcedef + /CurFormCache 0 .forcedef + /CurOutlineCache 0 .forcedef + /CurPatternCache 0 .forcedef + /CurUPathCache 0 .forcedef + /CurScreenStorage 0 .forcedef + /CurSourceList 0 .forcedef + /DoPrintErrors false .forcedef + /MaxDisplayList 140000 .forcedef + /MaxFormCache 100000 .forcedef + /MaxOutlineCache 65000 .forcedef + /MaxPatternCache 100000 .forcedef + /MaxUPathCache 300000 .forcedef + /MaxScreenStorage 84000 .forcedef + /MaxSourceList 25000 .forcedef + /RamSize 4194304 .forcedef +end + +% ------ Miscellaneous ------ % + +(<<) cvn % - << -mark- + /mark load def +(>>) cvn % -mark- ... >> + /.dicttomark load def +/languagelevel 2 def +% When running in Level 2 mode, this interpreter is supposed to be +% compatible with Adobe version 2017. +/version (2017) readonly def + +% If binary tokens are supported by this interpreter, +% set an appropriate default binary object format. +/setobjectformat where + { pop + /RealFormat getsystemparam (IEEE) eq { 1 } { 3 } ifelse + /ByteOrder getsystemparam { 1 add } if + setobjectformat + } if + +% ------ Virtual memory ------ % + +/currentglobal % - currentglobal + /currentshared load def +/gcheck % gcheck + /scheck load def +/setglobal % 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 + +% VMReclaim and VMThreshold are user parameters. +/setvmthreshold { % setvmthreshold - + mark /VMThreshold 2 index .dicttomark setuserparams pop +} odef +/vmreclaim { % vmreclaim - + dup 0 gt { + .vmreclaim + } { + mark /VMReclaim 2 index .dicttomark setuserparams pop + } ifelse +} odef +-1 setvmthreshold + +% ------ IODevices ------ % + +/.getdevparams where { + pop /currentdevparams { % currentdevparams + .getdevparams .dicttomark + } odef +} if +/.putdevparams where { + pop /setdevparams { % setdevparams - + mark 1 index { } forall counttomark 2 add index + .putdevparams pop pop + } 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 + +end % serverdict + +% Because there may be objects on the e-stack created since the job save, +% we have to clear the e-stack before doing the end-of-job restore. +% We do this by executing a 2 .stop, which is caught by the 2 .stopped +% in .runexec; we leave on the o-stack a procedure to execute aftewards. +% +%**************** The definition of startjob is not complete yet, since +% it doesn't reset stdin/stdout. +/.startnewjob { % + % .startnewjob - + 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 + % The Adobe documentation doesn't say what happens to the + % graphics state stack in this case, but an experiment + % produced results suggesting that a grestoreall occurs. + grestoreall + } { + % Encapsulated job + pop + serverdict /.jobsave save put + serverdict /.jobsavelevel 1 put + .userdict /quit /stop load put + } ifelse + % Reset the interpreter state. + clear cleardictstack + initgraphics + false setglobal +} bind def +/.startjob { % + % .startjob + vmstatus pop pop serverdict /.jobsavelevel get eq + 2 index .checkpassword 0 gt and { + exch .checkpassword exch count 3 roll count 3 sub { pop } repeat + cleardictstack + % Reset the e-stack back to the 2 .stopped in .runexec, + % passing the finish_proc to be executed afterwards. + 2 .stop + } { % Password check failed + pop pop pop false + } ifelse +} odef +/startjob { % startjob + { .startnewjob true } .startjob +} odef + +systemdict begin +/quit { % - quit - + //systemdict begin serverdict /.jobsave get null eq + { end //quit } + { /quit load /invalidaccess /signalerror load end exec } + ifelse +} bind odef +end + +% We would like to define exitserver as a procedure, using the code +% that the Red Book says is equivalent to it. However, since startjob +% resets the exec stack, we can't do this, because control would never +% proceed past the call on startjob if the exitserver is successful. +% Instead, we need to construct exitserver out of pieces of startjob. + +serverdict begin + +/exitserver { % exitserver - + true exch { .startnewjob } .startjob not { + /exitserver /invalidaccess signalerror + } if +} bind def + +end % serverdict + +% ------ 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. + +/.dict1 { exch mark 3 1 roll .dicttomark } bind def + +currentglobal false setglobal 25 dict exch setglobal begin +currentsystemparams + +% The following do not depend on the presence of setpagedevice. +/buildtime 1 index /BuildTime get def +/byteorder 1 index /ByteOrder get def +/checkpassword { .checkpassword 0 gt } bind def +dup /DoStartPage known + { /dostartpage { /DoStartPage getsystemparam } bind def + /setdostartpage { /DoStartPage .dict1 setsystemparams } bind def + } if +dup /StartupMode known + { /dosysstart { /StartupMode getsystemparam 0 ne } bind def + /setdosysstart { { 1 } { 0 } ifelse /StartupMode .dict1 setsystemparams } bind def + } if +%****** Setting jobname is supposed to set userparams.JobName, too. +/jobname { /JobName getuserparam } bind def +/jobtimeout { /JobTimeout getuserparam } bind def +/ramsize { /RamSize getsystemparam } bind def +/realformat 1 index /RealFormat get def +dup /PrinterName known + { /setprintername { /PrinterName .dict1 setsystemparams } bind def + } if +/printername + { currentsystemparams /PrinterName .knownget not { () } if exch copy + } bind def +currentuserparams /WaitTimeout known + { /waittimeout { /WaitTimeout getuserparam } bind def + } if + +% The following do require setpagedevice. +/.setpagedevice where { pop } { (%END PAGEDEVICE) .skipeof } ifelse +/defaulttimeouts + { currentsystemparams dup + /JobTimeout .knownget not { 0 } if + exch /WaitTimeout .knownget not { 0 } if + currentpagedevice /ManualFeedTimeout .knownget not { 0 } if + } bind def +/margins + { currentpagedevice /Margins .knownget { exch } { [0 0] } ifelse + } bind def +/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 +/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 +/.setpagesize { 2 array astore /PageSize .dict1 setpagedevice } bind def +/setduplexmode { /Duplex .dict1 setpagedevice } bind def +/setmargins + { exch 2 array astore /Margins .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 +%END PAGEDEVICE + +% The following are not implemented yet. +%manualfeed +%manualfeedtimeout +%pagecount +%pagestackorder +%setpagestackorder + +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 .forcedef % statusdict is local, systemdict is global + +% ------ Color spaces ------ % + +% Define the setcolorspace procedures: +% proc +/colorspacedict mark + /DeviceGray { pop 0 setgray null } bind + /DeviceRGB { pop 0 0 0 setrgbcolor null } bind + /setcmykcolor where + { pop /DeviceCMYK { pop 0 0 0 1 setcmykcolor null } bind + } if + /.setcieaspace where + { pop /CIEBasedA { NOCIE { pop 0 setgray null } { dup 1 get .setcieaspace } ifelse } bind + } if + /.setcieabcspace where + { pop /CIEBasedABC { NOCIE { pop 0 0 0 setrgbcolor null } { dup 1 get .setcieabcspace } ifelse } bind + } if + /.setciedefspace where + { pop /CIEBasedDEF { NOCIE { pop 0 0 0 setrgbcolor null } { dup 1 get .setciedefspace } ifelse } bind + } if + /.setciedefgspace where + { pop /CIEBasedDEFG { NOCIE { pop 0 0 0 1 setcmykcolor null } { dup 1 get .setciedefgspace } ifelse } bind + } if + /.setseparationspace where + { pop /Separation { dup 2 get setcolorspace dup .setseparationspace } bind + } if + /.setindexedspace where + { pop /Indexed { dup 1 get setcolorspace dup .setindexedspace } bind + } if + /.nullpatternspace [/Pattern] readonly def + /.setpatternspace where + { pop /Pattern + { dup type /nametype eq { pop //.nullpatternspace } if + dup length 1 gt { dup 1 get setcolorspace } if + dup .setpatternspace + } bind + } if + /.setdevicenspace where + { pop /DeviceN { dup 2 get setcolorspace dup .setdevicenspace } bind + } if + /.setdevicepixelspace where + { pop /DevicePixel { dup .setdevicepixelspace } bind + } if + currentdict /.nullpatternspace .undef +.dicttomark def + +/.devcs [ + /DeviceGray /DeviceRGB /DeviceCMYK /DevicePixel +] readonly def +/currentcolorspace { % - currentcolorspace + .currentcolorspace dup type /integertype eq { + //.devcs exch 1 getinterval + } if +} odef +currentdict /.devcs .undef + +/setcolorspace { % setcolorspace - + dup dup dup type /nametype ne { 0 get } if + //colorspacedict exch get exec + dup null eq { pop } { .setcolorspace } ifelse pop +} odef + +% ------ CIE color rendering ------ % + +% Define findcolorrendering and a default ColorRendering ProcSet. + +/findcolorrendering { % findcolorrendering + % + /ColorRendering /ProcSet findresource + 1 index .namestring (.) concatstrings + 1 index /GetPageDeviceName get exec .namestring (.) concatstrings + 2 index /GetHalftoneName get exec .namestring + concatstrings concatstrings + dup /ColorRendering resourcestatus { + pop pop exch pop exch pop true + } { + pop /GetSubstituteCRD get exec false + } ifelse +} odef + +5 dict dup begin + +/GetPageDeviceName { % - GetPageDeviceName + currentpagedevice dup /PageDeviceName .knownget { + exch pop + } { + pop /none + } ifelse +} bind def + +/GetHalftoneName { % - GetHalftoneName + currenthalftone /HalftoneName .knownget not { /none } if +} bind def + +/GetSubstituteCRD { % GetSubstituteCRD + pop /DefaultColorRendering +} bind def + +end +% The resource machinery hasn't been activated, so just save the ProcSet +% and let .fixresources finish the installation process. +/ColorRendering exch def + +% Define setcolorrendering. + +/.colorrenderingtypes 5 dict def + +/setcolorrendering { % setcolorrendering - + dup /ColorRenderingType get //.colorrenderingtypes exch get exec +} odef + +/.setcolorrendering1 where { pop } { (%END CRD) .skipeof } ifelse + +.colorrenderingtypes 1 { + dup .buildcolorrendering1 .setcolorrendering1 +} .bind put + +% Initialize the default CIE rendering dictionary. +% 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. +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] readonly + /TransformPQR + [ {exch pop exch pop exch pop exch pop} bind dup dup ] readonly + /RangeLMN [0 0.9505 0 1 0 1.0890] readonly + /MatrixABC + [ 3.24063 -0.96893 0.05571 + -1.53721 1.87576 -0.20402 + -0.49863 0.04152 1.05700 + ] readonly + /EncodeABC [ {0 .max 0.45 exp} bind dup dup] readonly + /WhitePoint [0.9505 1 1.0890] readonly + % Some Genoa tests seem to require the presence of BlackPoint. + /BlackPoint [0 0 0] readonly +.dicttomark setcolorrendering + +%END CRD + +% Initialize a CIEBased color space for sRGB. +/CIEsRGB [ /CIEBasedABC + mark + /DecodeLMN [ { + dup 0.03928 le { 12.92321 div } { 0.055 add 1.055 div 2.4 exp } ifelse + } bind dup dup ] readonly + /MatrixLMN [ + 0.412457 0.212673 0.019334 + 0.357576 0.715152 0.119192 + 0.180437 0.072175 0.950301 + ] readonly + /WhitePoint [0.9505 1.0 1.0890] readonly + .dicttomark readonly +] readonly def + +% ------ Painting ------ % + +% A straightforward definition of execform that doesn't actually +% do any caching. +/.execform1 { + % This is a separate operator so that the stacks will be restored + % properly if an error occurs. + dup /Matrix get concat + dup /BBox get aload pop + exch 3 index sub exch 2 index sub rectclip + dup /PaintProc get + 1 index /Implementation known not { + 1 index dup /Implementation null .forceput readonly pop + } if + exec +} .bind odef % must bind .forceput + +/.formtypes 5 dict + dup 1 /.execform1 load put +def + +/execform { %
execform - + gsave { + dup /FormType get //.formtypes exch get exec + } stopped grestore { stop } if +} odef + +/.patterntypes 5 dict + dup 1 /.buildpattern1 load put +def + +/makepattern { % makepattern + //.patterntypes 2 index /PatternType get get + .currentglobal false .setglobal exch + % Stack: proto matrix global buildproc + 3 index dup length 1 add dict .copydict + 3 index 3 -1 roll exec 3 -1 roll .setglobal + 1 index /Implementation 3 -1 roll put + readonly exch pop exch pop +} odef + +/setpattern { % [ ...] setpattern - + currentcolorspace 0 get /Pattern ne { + [ /Pattern currentcolorspace ] setcolorspace + } if setcolor +} odef + +% Extend image and imagemask to accept dictionaries. +% We must create .imagetypes and .imagemasktypes outside level2dict, +% and leave some extra space because we're still in Level 1 mode. +systemdict begin +/.imagetypes 5 dict + dup 1 /.image1 load put +def +/.imagemasktypes 5 dict + dup 1 /.imagemask1 load put +def +end + +/.image /image load def +/image { + dup type /dicttype eq { + dup /ImageType get //.imagetypes exch get exec + } { + //.image + } ifelse +} odef +currentdict /.image undef + +/.imagemask /imagemask load def +/imagemask { + dup type /dicttype eq { + dup /ImageType get //.imagemasktypes exch get exec + } { + //.imagemask + } ifelse +} odef +currentdict /.imagemask undef + +end % level2dict diff --git a/pstoraster/gs_ll3.ps b/pstoraster/gs_ll3.ps new file mode 100644 index 0000000000..acf701ec67 --- /dev/null +++ b/pstoraster/gs_ll3.ps @@ -0,0 +1,387 @@ +% Copyright (C) 1997, 1998 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 supports the work of the GNU Project, but is not +% affiliated with the Free Software Foundation or the GNU Project. GNU +% Ghostscript, as distributed by Aladdin Enterprises, does not require any +% GNU software to build or run it. + +% $Id: gs_ll3.ps 956 2000-03-08 23:15:43Z mike $ +% Initialization file for PostScript LanguageLevel 3 functions. +% Essentially all of these are stubs right now. +% This file must be loaded after gs_lev2.ps and gs_res.ps. +% These definitions go into ll3dict or various ProcSets. +% NOTE: the interpreter creates ll3dict. + +ll3dict begin + +% We need LanguageLevel 2 or higher in order to have setuserparams and +% defineresource. +languagelevel dup 2 max .setlanguagelevel + +% ------ Idiom recognition ------ % + +/IdiomRecognition false .definepsuserparam + +% Modify `bind' to apply idiom recognition afterwards. +/.bindscratch 128 string def +% Do the right thing if NOBIND or DELAYBIND is in effect. +% Note also that since this definition of `bind' may get bound in, +% it has to function properly even at lower language levels, +% where IdiomRecognition may not be defined. +/bind load /.bind load ne +/bind { % bind + //.bind currentuserparams /IdiomRecognition + .knownget not { false } if { + (*) { + /IdiomSet findresource + false exch { + % Stack: proc false dummykey [template substitute] + exch pop dup 1 get exch 0 get + % Stack: proc false substitute template + 3 index .eqproc { + 2 index gcheck 1 index gcheck not and { + pop + } { + 3 -1 roll pop exch not exit + } ifelse + } { + pop + } ifelse + } forall { exit } if + } //.bindscratch /IdiomSet resourceforall + } if +} odef +{ /.bind /bind load def + /bind { } def +} if +currentdict /.bindscratch .undef + +% ------ HalftoneTypes 6, 10, 16 ------ % + +% This code depends on one new operator: +% +% .setstriphalftone - +% +% is the dictionary that will be returned by .currenthalftone. +% The operator only looks at the TransferFunction entry. +% Width, Height: as for HalftoneType 3. +% Thresholds: a BigStringEncode filter holding the thresholds, +% Width x Height x BitsPerSample / 8 bytes. +% shift: the amount of X shift per Y repetition of the halftone, +% 0 <= Shift < Width. +% bits: bits per sample, 8 or 16. +% +% Eventually the code below will have to get hooked up to sethalftone +% and currenthalftone.... + +/.copybytes { % .copybytes - + { 1 index read not { /sethalftone load /rangecheck signalerror exit } if + 1 index exch write + } repeat pop pop +} bind def + +/.copythresholds { % .copythresholds - + dup 8 idiv 3 index mul 2 index mul + dup /BigStringEncode filter 3 1 roll + % Stack: dict width height dest bits nbytes + 5 index /Thresholds get 3 index 3 -1 roll .copybytes + 1 index closefile + 0 .setstriphalftone +} bind def + +/.sethalftone6 { % .sethalftone6 - + % Keys: Width, Height, Thresholds, T'Function + dup /Width get 1 index /Height get + 8 .copythresholds +} odef + +/.copythresholds2 { % + % .copythresholds2 - +% The block height B is gcd(Height, Height2). + 3 index 2 index { + 2 copy lt { exch } if dup 1 eq { pop exit } if exch 1 index mod + } loop +% The raster R is (Width * Height + Width2 * Height2) / B * bits/8. + 5 index 5 index mul 4 index 4 index mul add 1 index idiv + 2 index 8 idiv mul +% Currently I don't know how to compute the stride. +% ****** COMPUTE THE STRIDE SOMEHOW ****** +% Push additional arguments onto the stack. + 1 index 1 index mul /BigStringEncode filter 4 1 roll + 9 index /Thresholds get + % Stack: dict width height width2 height2 bits + % dest B R stride source +% For the first rectangle, the number of blocks is Height / B; +% the offset is 0. + 5 copy 14 index 5 1 roll + 14 index 5 index idiv 4 1 roll + 0 exch .copyshifted +% For the second rectangle, the number of blocks is Height2 / B; +% the offset is Width. + 5 copy 12 index 5 1 roll + 12 index 4 index idiv 4 1 roll + 16 index exch .copyshifted + % Stack: dict width height width2 height2 bits + % dest B R stride source + % We want: dict R/(bits/8) B dest bits stride + pop exch 4 index 8 idiv idiv 4 1 roll + % R/(bits/8) dest B stride + exch 3 1 roll 5 -1 roll exch + 9 -4 roll 4 { pop } repeat + .setstriphalftone +} bind def + +% Copy a shifted rectangular threshold array into a BigStringEncode filter. +% Note that the width and shift are in bytes, not samples. +/.copyshifted { % + % .copyshifted - +% Copy N blocks of x B bytes from . +% Row Y (0 <= Y < B) in group G (0 <= G < N) must get copied to byte position +% Y * R + (G * stride + offset) mod R +% in the destination. + 1 index % Stack: ... rowstart + 6 index { % iterate over rows within a block + 5 index { % iterate over blocks + 8 index 1 index setfileposition + 1 index 9 index 9 index .copybytes + 4 index add % + raster + } repeat % end block + 3 index add 4 index mod % + stride, mod raster + } repeat % end row in block + 9 { pop } repeat +} bind def + +/.sethalftone10 { % .sethalftone10 - + % Keys: XSquare, YSquare, Thresholds, T'Function +% ****** DOESN'T HANDLE STRING SOURCE ****** + dup /XSquare get dup 2 index /YSquare get dup + 8 .copythresholds2 +} odef + +/.sethalftone16 { % .sethalftone16 - + % Keys: Width, Height, Width2, Height2, + % Thresholds, T'Function + dup /Width get 1 index /Height get + 2 index /Width2 .knownget { % 2-rectangle case + 3 index /Height2 get + 16 .copythresholds2 + } { % 1-rectangle case + 16 .copythresholds + } ifelse +} odef + +{6 10 16} { dup /HalftoneType defineresource pop } forall + +% ------ ImageTypes 3 and 4 (masked images) ------ % + +.imagetypes + dup 3 /.image3 load put + 4 /.image4 load put + +% ------ Functions ------ % + +% Define the FunctionType resource category. +/Generic /Category findresource dup maxlength 3 add dict .copydict begin + /InstanceType /integertype def +/FunctionType currentdict end /Category defineresource pop + +{0 2 3} { dup /FunctionType defineresource pop } forall + +% ------ Smooth shading ------ % + +% Define the ShadingType resource category. +/Generic /Category findresource dup maxlength 3 add dict .copydict begin + /InstanceType /integertype def +/ShadingType currentdict end /Category defineresource pop + +systemdict /.shadingtypes mark % not ll3dict + 1 /.buildshading1 load + 2 /.buildshading2 load + 3 /.buildshading3 load + 4 /.buildshading4 load + 5 /.buildshading5 load + 6 /.buildshading6 load + 7 /.buildshading7 load +.dicttomark put + +/.buildshading { % .buildshading + % The .buildshading operators use the current color space + % for ColorSpace. + dup /ShadingType get //.shadingtypes exch get + 1 index /ColorSpace get gsave { setcolorspace exec } stopped + grestore { stop } if +} bind def +/.buildpattern2 { %